﻿//-----------------------------------------------------------------------------
//<filedescription file="IntegrationKit.OSD.cs" company="Microsoft">
//  <copyright>
//     Copyright © Microsoft Corporation.  All rights reserved.
//     ***  DESIGNATED SAMPLE CODE (per the included software license terms) ***
//      THIS CODE SAMPLE IS MADE AVAILABLE TO YOU WITHOUT WARRANTY OF ANY KIND
//      AND CONFERS NO RIGHTS ON YOU WHATSOEVER EXCEPT THE RIGHT TO REVIEW IT
//      SOLELY AS A REFERENCE.  THE ENTIRE RISK OF USE OR RESULTS FROM USE OF
//      THIS CODE SAMPLE REMAINS WITH YOU.
//  </copyright>
//  <purpose>
//     Provides utility methods specific to Configuration Manager
//     OS Deployment features
//  </purpose>
//  <notes>
//  </notes>
//</filedescription>
//-----------------------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Resources;
using System.Windows.Forms;
using System.Xml;
using Microsoft.ConfigurationManagement.AdminConsole;
using Microsoft.ConfigurationManagement.AdminConsole.OsdCommon;
using Microsoft.ConfigurationManagement.AdminConsole.TaskSequenceEditor;
using Microsoft.ConfigurationManagement.ManagementProvider;
using Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine;


namespace Microsoft.ConfigurationManagement.IntegrationDevelopmentKit
{
    /// <summary>
    /// 
    /// </summary>
    public partial class IntegrationKitUtilities
    {
        #region OSD-specific object instantiation classes

        /// <summary>
        ///     
        /// </summary>
        /// <remarks>
        ///     
        /// </remarks>
        public const string SUPPORTED_OS_WINPE_AND_FULL_OS = "WinPEandFullOS";
        /// <summary>
        ///     
        /// </summary>
        /// <remarks>
        ///     
        /// </remarks>
        public const string SUPPORTED_OS_WINPE = "FullOS";
        /// <summary>
        ///     
        /// </summary>
        /// <remarks>
        ///     
        /// </remarks>
        public const string SUPPORTED_OS_FULL_OS = "WinPE";

        /// <summary>
        /// 
        /// </summary>
        public class SMS_TaskSequence_Reference
        {
            /// <summary>
            /// 
            /// </summary>
            public string Package;
            /// <summary>
            /// 
            /// </summary>
            public string Program;
        };
       
        /// <summary>
        /// 
        /// </summary>
        public class SMS_TaskSequencePackage
        {
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int ActionInProgress;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string AlternateContentProviders;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string BootImageID;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string Category;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string CustomProgressMsg;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string DependentProgram;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string Description;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int Duration;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public byte[] ExtendedData;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int ExtendedDataSize;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int ForcedDisconnectDelay;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public bool ForcedDisconnectEnabled;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int ForcedDisconnectNumRetries;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public byte[] Icon;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int IconSize;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public bool IgnoreAddressSchedule;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public byte[] ISVData;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int ISVDataSize;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string Language;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public DateTime LastRefreshTime;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string Manufacturer;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string MIFFilename;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string MIFName;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string MIFPublisher;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string MIFVersion;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string Name;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string PackageID;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int PackageType;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int PkgFlags;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int PkgSourceFlag;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string PkgSourcePath;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string PreferredAddressType;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int Priority;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int ProgramFlags;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public SMS_TaskSequence_Reference[] References;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public bool RefreshPkgSourceFlag;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public ScheduleToken[] RefreshSchedule;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string Reserved;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string Sequence;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string ShareName;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int ShareType;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public DateTime SourceDate;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string SourceSite;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int SourceVersion;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string StoredPkgPath;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int StoredPkgVersion;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public OSDetails[] SupportedOperatingSystems;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int TaskSequenceFlags;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int Type;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string Version;

        }
        
        /// <summary>
        /// 
        /// </summary>
        public class ScheduleToken
        {
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int DayDuration;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int HourDuration;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public bool IsGMT;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public int MinuteDuration;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public DateTime StartTime;
        }
        
        /// <summary>
        /// 
        /// </summary>
        public class OSDetails
        {
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string MaxVersion;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string MinVersion;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string Name;
            /// <summary>
            ///     
            /// </summary>
            /// <remarks>
            ///     
            /// </remarks>
            public string Platform;
        }


        #endregion
        
        #region Task Sequences



        /// <summary>
        ///     
        /// </summary>
        /// <param name="connection" type="Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine.WqlConnectionManager">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A Microsoft.ConfigurationManagement.ManagementProvider.IResultObject value...
        /// </returns>
        public static IResultObject CreateTaskSequence(WqlConnectionManager connection)
        {
            try
            {
                if (connection == null)
                {
                    throw new ArgumentNullException("connection");
                }

                IResultObject taskSequence = connection.CreateInstance("SMS_TaskSequence");
                if ((taskSequence == null) ||
                    (string.Compare(taskSequence.ObjectClass, "SMS_TaskSequence", StringComparison.OrdinalIgnoreCase) != 0))
                {
                    throw new Exception(Properties.Resources.Exception_CreatingSMS_TaskSequence_Instance);
                }
                return taskSequence;
            }
            catch (Exception e)
            {
                throw new Exception(Properties.Resources.Exception_CreatingSMS_TaskSequence_Instance, e.InnerException);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="xmlImport"></param>
        /// <returns></returns>
        public static IResultObject CreateTaskSequenceFromXml(WqlConnectionManager connection, XmlDocument xmlImport)
        {
            try
            {
                if (connection == null)
                {
                    throw new ArgumentNullException("connection");
                }

                if (xmlImport == null)
                {
                    throw new ArgumentNullException("xmlImport");
                }

                XmlNode testNode = GetXmlNode(xmlImport, "//sequence");
                if (testNode == null)
                {
                    DialogHelper.ShowMessageBox(Properties.Resources.Error_TaskSequenceXmlInvalid);
                    LogLine(LogFile, Properties.Resources.Error_TaskSequenceXmlInvalid, DebugEnabled);
                    return null;
                }

                //string sequence = xmlImport.OuterXml;
                string sequence = testNode.OuterXml;
                //DialogHelper.ShowMessageBox(xmlImport.OuterXml);

                if (string.IsNullOrEmpty(sequence))
                {
                    DialogHelper.ShowMessageBox(Properties.Resources.Error_FailedToImportTaskSequenceXml);
                    LogLine(LogFile, Properties.Resources.Error_FailedToImportTaskSequenceXml, DebugEnabled);
                    return null;
                }

                // this section to be replaced later with code to convert the task sequence XML into an IResultObject via programmatic import of the task steps


                IResultObject taskSequence = null;
                //DialogHelper.ShowMessageBox("Creating tasksequence");
                Dictionary<string, object> inParams = new Dictionary<string, object>();
                inParams.Add("Xml", sequence);

                IResultObject outParams = connection.ExecuteMethod("SMS_TaskSequence", "LoadFromXml", inParams);
                if ((outParams == null) ||
                    (string.Compare(outParams.ObjectClass, "__PARAMETERS", StringComparison.OrdinalIgnoreCase) != 0))
                {
                    DialogHelper.ShowMessageBox(Properties.Resources.Error_FailedToImportTaskSequenceXml);
                    LogLine(LogFile, Properties.Resources.Error_FailedToImportTaskSequenceXml, DebugEnabled);
                    return null;
                }

                taskSequence = outParams.GetSingleItem("ReturnValue");

                if ((taskSequence == null) ||
                    (string.Compare(taskSequence.ObjectClass, "SMS_TaskSequence", StringComparison.OrdinalIgnoreCase) != 0))
                {
                    DialogHelper.ShowMessageBox(Properties.Resources.Error_FailedToImportTaskSequenceXml);
                    LogLine(LogFile, Properties.Resources.Error_FailedToImportTaskSequenceXml, DebugEnabled);
                    return null;
                }

                return taskSequence;
            }
            catch (Exception ex)
            {
                DialogHelper.ShowMessageBox(Properties.Resources.Error_FailedToImportTaskSequenceXml);
                LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        ///     
        /// </summary>
        /// <param name="connection" type="Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine.WqlConnectionManager">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A Microsoft.ConfigurationManagement.ManagementProvider.IResultObject value...
        /// </returns>
        public static IResultObject CreateTaskSequencePackage(WqlConnectionManager connection)
        {
            try
            {
                if (connection == null)
                {
                    throw new ArgumentNullException("connection");
                }

                //if (taskSequence == null)
                //{
                //    throw new ArgumentNullException("taskSequence");
                //}


                // Create the new task sequence package.
                IResultObject taskSequencePackage = connection.CreateInstance("SMS_TaskSequencePackage");
                if ((taskSequencePackage == null) ||
                    (string.Compare(taskSequencePackage.ObjectClass, "SMS_TaskSequencePackage", StringComparison.OrdinalIgnoreCase) != 0))
                {
                    MessageBox.Show("CreateTaskSequencePackage: Unable to create an instance of SMS_TaskSequencePackage.");
                    return null;
                }
                taskSequencePackage["Name"].StringValue = "New task sequence package";

                
                
                return taskSequencePackage;
            }
            catch (SmsException ex)
            {
                LogLine(LogFile, "Failed to create Task Sequence: " + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param taskName="connection"></param>
        /// <param taskName="taskSequencePackage"></param>
        /// <param taskName="taskSequence"></param>
        /// <returns></returns>
        public static IResultObject AddTaskSequenceToPackage(WqlConnectionManager connection, IResultObject taskSequencePackage, IResultObject taskSequence)
        {
            try
            {
                Dictionary<string, object> inParams = new Dictionary<string, object>();
               
                // Set up parameters that associate the task sequence with the package.
                inParams.Add("TaskSequence", taskSequence);
                inParams.Add("TaskSequencePackage", taskSequencePackage);

                // Associate the task sequence with the package. Note that a call to Put is not required.
                IResultObject outParams = connection.ExecuteMethod("SMS_TaskSequencePackage", "SetSequence", inParams);

                // dispose result object with secure strings
                taskSequence.Dispose();
                
                if ((outParams == null) || 
                    (outParams["ReturnValue"].IntegerValue != 0))
                {
                    MessageBox.Show("CreateTaskSequencePackage: Setting the sequence in the package returned null.");
                    return null;
                }
                string packagePath = string.Empty;

                if (outParams["SavedTaskSequencePackagePath"].ObjectValue != null)
                {
                    packagePath = outParams["SavedTaskSequencePackagePath"].StringValue;
                }
                if (string.IsNullOrEmpty(packagePath))
                {
                    MessageBox.Show("CreateTaskSequencePackage: Setting the sequence in the package returned null.");
                    return null;
                }

                
                // SetSequence(SavedTaskSequencePackagePath) will return the WMI object path of the saved TSPackage
                // 'Clone' the instance returned by SMS provider
                IResultObject tspkg = connection.GetInstance(packagePath);
                if ((tspkg == null) || 
                    (string.Compare(tspkg.ObjectClass, "SMS_TaskSequencePackage", StringComparison.OrdinalIgnoreCase) != 0))
                {
                    return null;
                }
                return tspkg;

            }
            catch (Exception ex)
            {
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="editor"></param>
        /// <param name="parentNode"></param>
        /// <param name="taskSequencePackage"></param>
        /// <returns></returns>
        public static IResultObject GetTaskSequenceOpenInEditor(WqlConnectionManager conn, TaskSequenceEditorDialog editor, SmsTreeNode parentNode, out IResultObject taskSequencePackage)
        {
            ArgumentNotNull(editor, "editor");
            ArgumentNotNull(conn, "conn");
            ArgumentNotNull(parentNode, "parentNode");

            try
            {
                //modified 1/12/08 by rhearn to fix an internationalization issue 
                // (where different language installs had a different TSE title, causing this to fail)
                
                //get the full title from the task sequence editor dialog
                string editorTitle = editor.Text.Trim();

                //now get a list of all the task sequence packages in the site (yes, this is not very efficient)
                List<IResultObject> taskSeqPackages = new List<IResultObject>();
                taskSeqPackages = GetAllPackagesByType(conn, PackageType.TaskSequencePackage);
                IResultObject foundPackage = null;
                IResultObject taskSequence = null;

                if (taskSeqPackages != null)
                {
                    foreach (IResultObject tsPackage in taskSeqPackages)
                    {
                        
                        string packageName = GetROStringProperty(tsPackage, "Name");
                        string foundPackageName = string.Empty;
                        // if the package name is the same as what the start of the title of the dialog is, then this is a match.
                        if ((string.IsNullOrEmpty(packageName) == false) &&
                            (editorTitle.StartsWith(packageName, StringComparison.CurrentCultureIgnoreCase) == true))
                        {
                            if (TaskSequencesAreEqual(tsPackage, parentNode) == true)
                            {
                                // if this is the first match, then copy the object to be returned
                                if (foundPackage == null)
                                {
                                    foundPackage = tsPackage;
                                    foundPackageName = packageName;
                                }
                                //if another match was already found, check to see if this package title is longer
                                // if the title is longer and it is still a match for the task sequence editor title,
                                // then this task sequence is a better match.
                                else
                                {
                                    if (packageName.Length > foundPackageName.Length)
                                    {
                                        foundPackage = tsPackage;
                                        foundPackageName = packageName;
                                    }
                                    else if (packageName.Length == foundPackageName.Length)
                                    {
                                        //task sequence names are identical... can't distinguish which one should be used.
                                        DialogHelper.ShowMessageBox(Properties.Resources.Error_MultipleTaskSequencesByThisName);
                                 
                                    }
                                }

                            }
                            
                        }

                    }

                    if (foundPackage != null)
                    {
                        taskSequencePackage = foundPackage;
                        taskSequence = GetTaskSequenceFromTSPackage(conn, taskSequencePackage); 

                        return taskSequence;
                    }
                    else
                    {
                        //DialogHelper.ShowMessageBox(Properties.Resources.Error_NoTaskSequenceFoundInPackage);
                        taskSequencePackage = null; 
                        return null;
                    }
                }
                else
                {
                    //DialogHelper.ShowMessageBox(Properties.Resources.Error_TaskSequenceNameNotFound);
                    taskSequencePackage = null; 
                    return null;
                }
                //taskSequencePackage = null;
                //return null;

            }
            catch (Exception e)
            {
                DialogHelper.ShowMessageBox(e.Message);
                taskSequencePackage = null;
                return null;
            }

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="groupName"></param>
        /// <param name="groupDesc"></param>
        /// <param name="enabled"></param>
        /// <param name="continueOnError"></param>
        /// <returns></returns>
        public static IResultObject CreateTaskSequenceGroup(WqlConnectionManager connection, string groupName, string groupDesc, bool enabled, bool continueOnError)
        {
            try
            {
                IResultObject newGroup = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_Group");

                newGroup["Name"].StringValue = groupName;
                newGroup["Description"].StringValue = groupDesc;
                newGroup["Enabled"].BooleanValue = enabled;
                newGroup["ContinueOnError"].BooleanValue = continueOnError;
                return newGroup;
            }
            catch (Exception ex)
            {
                DialogHelper.ShowMessageBox("Exception occurred while trying to create the group!\n" + ex.Message);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }
       
        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="ro"></param>
        /// <param name="joinType"></param>
        /// <param name="firstExpression"></param>
        /// <param name="lastExpression"></param>
        /// <returns></returns>
        public static IResultObject JoinTaskSequenceConditionExpressions(WqlConnectionManager connection, IResultObject ro, string joinType, int firstExpression, int lastExpression)
        {
            try
            {

                IResultObject condition = null;

                if (ro["Condition"].ObjectValue == null)
                {
                    return ro;
                }
                else
                {
                    condition = ro.GetSingleItem("Condition");
                }

                List<IResultObject> operands = condition.GetArrayItems("Operands");
                if (operands.Count >= lastExpression + 1)
                {
                    IResultObject conditionOperator = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_ConditionOperator");

                    List<IResultObject> operatorOperands = operands.GetRange(firstExpression, ((lastExpression + 1) - firstExpression));
                    operands.RemoveRange(firstExpression, ((lastExpression + 1) - firstExpression));

                    conditionOperator.SetArrayItems("Operands", operatorOperands);
                    conditionOperator["OperatorType"].StringValue = joinType;

                    operands.Add(conditionOperator);
                    condition.SetArrayItems("Operands", operands);
                    ro.SetSingleItem("Condition", condition);
                }
                else
                {
                    DialogHelper.ShowMessageBox("Error during JoinTaskSequenceConditionExpressions: last expression > number of operands");
                }
                return ro;
            }
            catch (Exception ex)
            {
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }

        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="taskSequence"></param>
        /// <param name="taskSequencePackage"></param>
        /// <returns></returns>
        public static IResultObject SaveTaskSequenceToPackage(WqlConnectionManager connection, IResultObject taskSequence, IResultObject taskSequencePackage)
        {
            try
            {
                // Set up parameters that associate the task sequence with the package.
                Dictionary<string, object> inParams = new Dictionary<string, object>();
                inParams.Add("TaskSequence", taskSequence);
                inParams.Add("TaskSequencePackage", taskSequencePackage);

                // Associate the task sequence with the package. Note that a call to Put is not required.
                IResultObject result = connection.ExecuteMethod("SMS_TaskSequencePackage", "SetSequence", inParams);
                if (result != null && result["ReturnValue"].IntegerValue == 0)
                {
                    // SetSequence(SavedTaskSequencePackagePath) will return the WMI object path of the saved TSPackage
                    // 'Clone' the instance returned by SMS provider
                    //IResultObject tspkg = Conn.GetInstance(result["SavedTaskSequencePackagePath"].StringValue);
                    //Dictionary<string, object> inParams2 = new Dictionary<string, object>();
                    //result = tspkg.ExecuteMethod("AddChangeNotification", inParams2);
                    return taskSequencePackage;
                }
                else
                {
                    DialogHelper.ShowMessageBox("Error applying changes to task sequence! Error occurred at SetSequence.\n\n");
                    //PropMgr["AlreadySetGroups"].BooleanValue = false;
                    return null;
                }
            }
            catch (SmsException ex)
            {
                DialogHelper.ShowMessageBox("Failed to save Task Sequence to package: " + ex.Message);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        ///     
        /// </summary>
        /// <param name="connection" type="Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine.WqlConnectionManager">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="taskSequencePackage" type="Microsoft.ConfigurationManagement.ManagementProvider.IResultObject">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A System.Xml.XmlDocument value...
        /// </returns>
        public static XmlDocument ExportTaskSequenceXml(WqlConnectionManager connection, IResultObject taskSequencePackage)
        {
            try
            {
                if (connection == null)
                {
                    throw new ArgumentNullException("connection");
                }
                if (taskSequencePackage == null)
                {
                    throw new ArgumentNullException("taskSequencePackage");
                }

                XmlDocument doc = new XmlDocument();
                string sequence = GetROStringProperty(taskSequencePackage, "Sequence");
                if (string.IsNullOrEmpty(sequence))
                {
                    throw new ArgumentNullException("SMS_TaskSequencePackage.Sequence", "Property 'Sequence' was null.");
                }

                doc.LoadXml(sequence);
                XmlNode testNode = GetXmlNode(doc, "//sequence");
                if (testNode == null)
                {
                    DialogHelper.ShowMessageBox(Properties.Resources.Error_FailedToExportTaskSequenceXml);
                    LogLine(LogFile, Properties.Resources.Error_FailedToExportTaskSequenceXml, DebugEnabled);
                    return null;
                }
                return doc;
            }
            catch (Exception ex)
            {
                DialogHelper.ShowMessageBox(Properties.Resources.Error_FailedToExportTaskSequenceXml);
                LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        ///     
        /// </summary>
        /// <param name="connection" type="Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine.WqlConnectionManager">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="tsPackage" type="Microsoft.ConfigurationManagement.ManagementProvider.IResultObject">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="actionClassFullName" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// /// <param name="actionClassEndsWith" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A bool value...
        /// </returns>
        public static bool IsFirstActionTypeInSequence(WqlConnectionManager connection, IResultObject tsPackage, string actionClassFullName, string actionClassEndsWith)
        {
            if (string.IsNullOrEmpty(actionClassFullName) && string.IsNullOrEmpty(actionClassEndsWith))
            {
                throw new ArgumentException("Neither 'actionClass' string value was supplied");
            }
            if ((tsPackage == null) ||
                (string.Compare(tsPackage.ObjectClass, "SMS_TaskSequencePackage", StringComparison.OrdinalIgnoreCase) != 0))
            {
                MessageBox.Show(Properties.Resources.Error_TaskSequenceNameNotFound);
                return false;
            }

            int? stepQty = GetNumberOfTaskSequenceStepsOfType(connection, tsPackage, actionClassFullName, actionClassEndsWith);
            if (stepQty.HasValue == false)
            {
                //MessageBox.Show(Properties.Resources.Error_NoTaskSequenceFoundInPackage);
                return false;
            }
            else if (stepQty.Value == 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        #region --unused--


        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        public void EnumerateTaskSequencePackages(WqlConnectionManager connection)
        {
            try
            {
                IResultObject taskSequencePackages = ExecuteNullableQuery(connection, "select * from SMS_TaskSequencePackage");

                foreach (IResultObject ro in taskSequencePackages)
                {
                    ro.Get();

                    // Get the lazy properties - Sequence property contains the Task sequence XML.
                    LogLine(LogFile, ro["Name"].StringValue, DebugEnabled);
                    LogLine(LogFile, ro["Sequence"].StringValue, DebugEnabled);


                }
            }
            catch (Exception ex)
            {
                IntegrationKitUtilities.LogException(LogFile, ex);

            }
        }

        /// <summary>
        ///     
        /// </summary>
        /// <param name="connection" type="Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine.WqlConnectionManager">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="taskSequence" type="Microsoft.ConfigurationManagement.ManagementProvider.IResultObject">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="name" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="description" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="commandLine" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="enabled" type="bool">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="continueOnError" type="bool">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A Microsoft.ConfigurationManagement.ManagementProvider.IResultObject value...
        /// </returns>
        public IResultObject AddCommandLineAction(WqlConnectionManager connection, IResultObject taskSequence, string name, string description, string commandLine, bool enabled, bool continueOnError)
        {
            try
            {
                if (string.IsNullOrEmpty(commandLine))
                {
                    LogLine(LogFile, "ERROR: commandLine parameter was null", DebugEnabled);
                    return null;
                }
                if (string.IsNullOrEmpty(name))
                {
                    LogLine(LogFile, "ERROR: action name parameter was null", DebugEnabled);
                    return null;
                }

                // Create the new step.
                IResultObject ro;

                ro = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_RunCommandLineAction");
                ro["CommandLine"].StringValue = commandLine;

                ro["Name"].StringValue = name;
                ro["Description"].StringValue = description;
                ro["Enabled"].BooleanValue = enabled;
                ro["ContinueOnError"].BooleanValue = continueOnError;

                // Add the step to the task sequence.
                List<IResultObject> array = taskSequence.GetArrayItems("Steps");

                array.Add(ro);

                taskSequence.SetArrayItems("Steps", array);

                return taskSequence;
            }
            catch (Exception ex)
            {
                LogLine(LogFile, "Failed to add action: " + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }

        }
     
        /// <summary>
        /// 
        /// </summary>
        /// <param name="taskSequence"></param>
        /// <param name="indent"></param>
        public static void RecurseTaskSequenceSteps(IResultObject taskSequence, int indent)
        {
            try
            {
                // The array of SMS_TaskSequence_Steps.
                List<IResultObject> steps = taskSequence.GetArrayItems("Steps");

                foreach (IResultObject ro in steps)
                {
                    for (int i = 0; i < indent; i++)
                    {
                        Console.Write(" ");
                    }

                    if (ro["__CLASS"].StringValue == "SMS_TaskSequence_Group")
                    {
                        Console.Write("Group: ");
                    }

                    LogLine(LogFile, ro["Name"].StringValue, DebugEnabled);

                    // Child groups that are found. Use recursion to view them.
                    if (ro["__CLASS"].StringValue == "SMS_TaskSequence_Group")
                    {
                        RecurseTaskSequenceSteps(ro, indent + 3);
                    }
                }
            }
            catch (SmsException ex)
            {
                LogLine(LogFile, "Failed To enumerate task sequence items: " + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);

            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="taskSequencePackage"></param>
        /// <returns></returns>
        public IResultObject ReadTaskSequence(WqlConnectionManager connection, IResultObject taskSequencePackage)
        {
            IResultObject taskSequence = null;
            try
            {
                Dictionary<string, object> parameters = new Dictionary<string, object>();
                parameters.Add("TaskSequencePackage", taskSequencePackage);

                IResultObject outParams = connection.ExecuteMethod("SMS_TaskSequencePackage", "GetSequence", parameters);
                taskSequence = outParams.GetSingleItem("TaskSequence");

                return taskSequence;
            }
            catch (Exception ex)
            {
                LogLine(LogFile, "failed to hydrate: " + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="ro"></param>
        /// <param name="variableName"></param>
        /// <param name="variableValue"></param>
        /// <param name="conditionOperator"></param>
        /// <returns></returns>
        public IResultObject AddVariableCondition(WqlConnectionManager connection, IResultObject ro, string variableName, string variableValue, string conditionOperator)
        {
            try
            {

                if (ro != null)
                {
                    if ((variableName != null) && (variableValue != null) && (conditionOperator != null))
                    {
                        IResultObject condition = null;
                        if (ro["Condition"].ObjectValue == null)
                        {
                            condition = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_Condition");
                        }
                        else
                        {
                            condition = ro.GetSingleItem("Condition");
                        }

                        IResultObject variable = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_VariableConditionExpression");

                        variable["Variable"].StringValue = variableName;
                        variable["Value"].StringValue = variableValue;
                        variable["Operator"].StringValue = conditionOperator;

                        List<IResultObject> operands = condition.GetArrayItems("Operands");
                        operands.Add(variable);
                        condition.SetArrayItems("Operands", operands);
                        ro.SetSingleItem("Condition", condition);
                        return ro;
                    }
                    else
                    {
                        DialogHelper.ShowMessageBox("Error! Condition information passed in to AddVariableCondition was null!");
                        return null;
                    }
                }
                else
                {
                    DialogHelper.ShowMessageBox("Error! Object passed in to AddVariableCondition was null!");
                    return null;
                }
            }
            catch (Exception ex)
            {
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        //public IResultObject AddRebootActionToTaskSequence(WqlConnectionManager connection, IResultObject taskSequence, SMS_TaskSequence_RebootAction actionParams)
        //{
        //    try
        //    {
        //        if (connection == null)
        //        {
        //            LogLine(LogFile, "ERROR: connection object was null", DebugEnabled);
        //            return null;
        //        }

        //        if (taskSequence == null)
        //        {
        //            LogLine(LogFile, "ERROR: task sequence object was null", DebugEnabled);
        //            return null;
        //        }

        //        if (actionParams == null)
        //        {
        //            LogLine(LogFile, "ERROR: reboot action object object was null", DebugEnabled);
        //            return null;
        //        }


        //        // Create the new step.
        //        IResultObject rebootAction = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_RebootAction");
        //        if (rebootAction == null)
        //        {
        //            LogLine(LogFile, "ERROR: Unable to create an instance of SMS_TaskSequence_RebootAction", DebugEnabled);
        //            return null;
        //        }

        //        //now set all the properties
        //        rebootAction["ContinueOnError"].BooleanValue = actionParams.ContinueOnError;
        //        rebootAction["Description"].StringValue = actionParams.Description;
        //        rebootAction["Enabled"].BooleanValue = actionParams.Enabled;
        //        rebootAction["Message"].StringValue = actionParams.Message;
        //        rebootAction["MessageTimeout"].IntegerValue = actionParams.MessageTimeout;
        //        rebootAction["Name"].StringValue = actionParams.Name;
        //        rebootAction["SupportedEnvironment"].StringValue = actionParams.SupportedEnvironment;
        //        rebootAction["Target"].StringValue = actionParams.Target;
        //        rebootAction["Timeout"].IntegerValue = actionParams.Timeout;

        //        if (actionParams.Condition != null)
        //        {
        //            rebootAction = AddConditionToAction(connection, rebootAction, actionParams.Condition);
        //            if (rebootAction == null)
        //            {
        //                LogLine(LogFile, "ERROR: Failed to add condition to action.", DebugEnabled); 
        //                return null;
        //            }

        //        }
        //        // Add the step to the task sequence.
        //        List<IResultObject> arrayItems = taskSequence.GetArrayItems("Steps");

        //        arrayItems.Add(rebootAction);

        //        taskSequence.SetArrayItems("Steps", arrayItems);

        //        return taskSequence;
        //    }
        //    catch (Exception ex)
        //    {
        //        LogLine(LogFile, "Failed to add action: " + ex.Message, DebugEnabled);
        //        IntegrationKitUtilities.LogException(LogFile, ex);
        //        return null;
        //    }

        //}

        //public IResultObject AddConditionToAction(WqlConnectionManager connection, IResultObject action, SMS_TaskSequence_Condition condition)
        //{
        //    try
        //    {
        //        if (connection == null)
        //        {
        //            LogLine(LogFile, "ERROR: connection object was null", DebugEnabled);
        //            return null;
        //        }

        //        if (action == null)
        //        {
        //            LogLine(LogFile, "ERROR: action object was null", DebugEnabled);
        //            return null;
        //        }

        //        if (condition == null)
        //        {
        //            LogLine(LogFile, "ERROR: condition object object was null", DebugEnabled);
        //            return null;
        //        }

        //        if (condition.Operands == null)
        //        {
        //            LogLine(LogFile, "ERROR: No operands found in the condition!", DebugEnabled);
        //            return null;
        //        }


        //        IResultObject newCondition = null;
        //        if (action["Condition"].ObjectValue == null)
        //        {
        //            // Create a new condition.
        //            newCondition = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_Condition");
        //            if (newCondition == null)
        //            {
        //                LogLine(LogFile, "ERROR: Failed to create a new instance of SMS_TaskSequence_Condition", DebugEnabled);
        //                return null;
        //            }
        //        }
        //        else
        //        {   // Get the existing condition.
        //            newCondition = action.GetSingleItem("Condition");
        //            if (newCondition == null)
        //            {
        //                LogLine(LogFile, "ERROR: Failed to get existing condition(s) from action", DebugEnabled);
        //                return null;
        //            }
        //        }

        //        List<IResultObject> conditionList = new List<IResultObject>();
        //        conditionList = CreateTaskSequenceConditions(connection, condition.Operands);
        //        if ((conditionList != null) && (conditionList.Count > 0))
        //        {
        //            newCondition.SetArrayItems("Operands", conditionList);
        //        }
        //        return newCondition;
        //    }
        //    catch (Exception ex)
        //    {
        //        LogLine(LogFile, "Failed to add condition to action: " + ex.Message, DebugEnabled);
        //        IntegrationKitUtilities.LogException(LogFile, ex);
        //        return null;
        //    }
        //}

        //public List<IResultObject> CreateTaskSequenceConditions(WqlConnectionManager connection, SMS_TaskSequence_ConditionOperand[] operands)
        //{
        //    // Each condition contains one or more condition operands.
        //    //
        //    // A condition operand is either (1) an expression, or (2) a condition operator (group of expressions with a join type):
        //    // 
        //    // When the condition contains a single expression or you have no nested expressions (i.e. grouped with "and", "or" or "not")
        //    //   the condition operands are the individual expressions, and are joined via an implied "and".
        //    //
        //    // When multiple operands are joined together using "and", "or", or "not", or when you have nested expression groups,
        //    //   they are combined into a condition operator, which contains a list of the expressions (and possibly other nested 
        //    //   condition operators / groups) and an operator type that defines the join.

        //    try
        //    {
        //        if (connection == null)
        //        {
        //            LogLine(LogFile, "ERROR: connection object was null", DebugEnabled);
        //            return null;
        //        }

        //        if (operands == null)
        //        {
        //            LogLine(LogFile, "ERROR: operands object object was null", DebugEnabled);
        //            return null;
        //        }

        //        List<IResultObject> operandsList = new List<IResultObject>();
        //        for (int i = 0; i < operands.Length; i++)
        //        {
        //            SMS_TaskSequence_ConditionOperand currentOperand = (SMS_TaskSequence_ConditionOperand)operands.GetValue(i) ;

        //            DialogHelper.ShowMessageBox("GetType().Name = " + currentOperand.GetType().Name + "\n" + 
        //                                        "GetType().BaseType = " + currentOperand.GetType().BaseType + "\n" +
        //                                        "GetType().DeclaringType = " + currentOperand.GetType().DeclaringType + "\n" +
        //                                        "GetType().DeclaringMethod = " + currentOperand.GetType().DeclaringMethod + "\n" +
        //                                        "GetType().FullName = " + currentOperand.GetType().FullName + "\n" +
        //                                        "GetType().IsNested = " + currentOperand.GetType().IsNested + "\n" +
        //                                        "GetType().ReflectedType = " + currentOperand.GetType().ReflectedType + "\n");


        //            if (string.Compare(currentOperand.GetType().DeclaringType.Name, "SMS_TaskSequence_ConditionOperator", StringComparison.OrdinalIgnoreCase) == 0)
        //            {
        //                //this is a condition operator, which contains other expressions or condition operands
        //                List<IResultObject> childOperands = new List<IResultObject>();

        //                SMS_TaskSequence_ConditionOperator newOperator = (SMS_TaskSequence_ConditionOperator)Convert.ChangeType(currentOperand, typeof(SMS_TaskSequence_ConditionOperator));
        //                if (newOperator == null)
        //                {
        //                    LogLine(LogFile, "ERROR: could not convert current operand to ConditionOperator type", DebugEnabled);
        //                    return null;
        //                }

        //                childOperands.AddRange(CreateTaskSequenceConditions(connection, newOperator.Operands));

        //                IResultObject newOperand = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_ConditionOperator");
        //                newOperand.SetArrayItems("Operands", childOperands);
        //                newOperand["OperatorType"].StringValue = newOperator.OperatorType;
        //                operandsList.Add(newOperand);
        //            }
        //            else
        //            {
        //                // this is an expression type. Go get the expression
        //                SMS_TaskSequence_ConditionExpression currentExpression = (SMS_TaskSequence_ConditionExpression)Convert.ChangeType(currentOperand, typeof(SMS_TaskSequence_ConditionExpression));
        //                if (currentExpression == null)
        //                {
        //                    LogLine(LogFile, "ERROR: could not convert current operand to ConditionExpression type", DebugEnabled);
        //                    return null;
        //                }
        //                IResultObject newExpression = CreateExpression(connection, currentExpression);
        //                if (newExpression == null)
        //                {
        //                    LogLine(LogFile, "ERROR: could not get the expression from the operand", DebugEnabled);
        //                    return null;
        //                }
        //                operandsList.Add(newExpression);
        //            }
        //        }

        //        return operandsList;

        //    }
        //    catch (Exception ex)
        //    {
        //        LogLine(LogFile, "Exception occurred in CreateTaskSequenceConditions:\n" + ex.Message, DebugEnabled);
        //        IntegrationKitUtilities.LogException(LogFile, ex);
        //        return null;
        //    }
        //}

        //public IResultObject CreateExpression(WqlConnectionManager connection, SMS_TaskSequence_ConditionExpression expression)
        //{
        //    string conditionType = expression.GetType().DeclaringType.Name;


        //    DialogHelper.ShowMessageBox("GetType().Name = " + expression.GetType().Name + "\n" + 
        //        "GetType().BaseType = " + expression.GetType().BaseType + "\n" +
        //        "GetType().DeclaringType = " + expression.GetType().DeclaringType + "\n" +
        //        "GetType().DeclaringMethod = " + expression.GetType().DeclaringMethod + "\n" +
        //        "GetType().FullName = " + expression.GetType().FullName + "\n" +
        //        "GetType().IsNested = " + expression.GetType().IsNested + "\n" +
        //        "GetType().ReflectedType = " + expression.GetType().ReflectedType + "\n");


        //    IResultObject newExpression = null;

        //    switch (conditionType.ToUpperInvariant())
        //    {
        //        case "SMS_TASKSEQUENCE_WMICONDITIONEXPRESSION":

        //            SMS_TaskSequence_WMIConditionExpression wmiCondition =
        //                (SMS_TaskSequence_WMIConditionExpression)Convert.ChangeType(expression, typeof(SMS_TaskSequence_WMIConditionExpression));

        //            newExpression = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_WMIConditionExpression");
        //            if (newExpression != null)
        //            {
        //                newExpression["Namespace"].StringValue = wmiCondition.Namespace;
        //                newExpression["Query"].StringValue = wmiCondition.Query;

        //            }
        //            break;

        //        case "SMS_TASKSEQUENCE_VARIABLECONDITIONEXPRESSION":
        //            SMS_TaskSequence_VariableConditionExpression varCondition =
        //                (SMS_TaskSequence_VariableConditionExpression)Convert.ChangeType(expression, typeof(SMS_TaskSequence_VariableConditionExpression));

        //            newExpression = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_VariableConditionExpression");
        //            if (newExpression != null)
        //            {
        //                newExpression["Operator"].StringValue = varCondition.Operator;
        //                newExpression["Variable"].StringValue = varCondition.Variable;
        //                if (string.IsNullOrEmpty(varCondition.Value))
        //                {
        //                    newExpression["Value"].StringValue = "";
        //                }
        //                else
        //                {
        //                    newExpression["Value"].StringValue = varCondition.Value;
        //                }

        //            }
        //            break;

        //        case "SMS_TASKSEQUENCE_SOFTWARECONDITIONEXPRESSION":
        //            SMS_TaskSequence_SoftwareConditionExpression swCondition =
        //                (SMS_TaskSequence_SoftwareConditionExpression)Convert.ChangeType(expression, typeof(SMS_TaskSequence_SoftwareConditionExpression));

        //            newExpression = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_SoftwareConditionExpression");
        //            if (newExpression != null)
        //            {
        //                newExpression["Operator"].StringValue = swCondition.Operator;
        //                newExpression["ProductCode"].StringValue = swCondition.ProductCode;
        //                if (string.IsNullOrEmpty(swCondition.ProductName))
        //                {
        //                    newExpression["ProductName"].StringValue = "";
        //                }
        //                else
        //                {
        //                    newExpression["ProductName"].StringValue = swCondition.ProductName;
        //                }
        //                if (string.IsNullOrEmpty(swCondition.UpgradeCode))
        //                {
        //                    newExpression["UpgradeCode"].StringValue = "";
        //                }
        //                else
        //                {
        //                    newExpression["UpgradeCode"].StringValue = swCondition.UpgradeCode;
        //                }

        //            } 
        //            break;

        //        case "SMS_TASKSEQUENCE_REGISTRYCONDITIONEXPRESSION":
        //            SMS_TaskSequence_RegistryConditionExpression regCondition =
        //                (SMS_TaskSequence_RegistryConditionExpression)Convert.ChangeType(expression, typeof(SMS_TaskSequence_RegistryConditionExpression));

        //            newExpression = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_RegistryConditionExpression");
        //            if (newExpression != null)
        //            {
        //                newExpression["Data"].StringValue = regCondition.Data;
        //                newExpression["KeyPath"].StringValue = regCondition.KeyPath;
        //                newExpression["Operator"].StringValue = regCondition.Operator;

        //                if (string.IsNullOrEmpty(regCondition.Type))
        //                {
        //                    newExpression["Type"].StringValue = "";
        //                }
        //                else
        //                {
        //                    newExpression["Type"].StringValue = regCondition.Type;
        //                }
        //                if (string.IsNullOrEmpty(regCondition.Value))
        //                {
        //                    newExpression["Value"].StringValue = "";
        //                }
        //                else
        //                {
        //                    newExpression["Value"].StringValue = regCondition.Value;
        //                }

        //            } 
        //            break;

        //        case "SMS_TASKSEQUENCE_FOLDERCONDITIONEXPRESSION":
        //            SMS_TaskSequence_FolderConditionExpression folderCondition =
        //              (SMS_TaskSequence_FolderConditionExpression)Convert.ChangeType(expression, typeof(SMS_TaskSequence_FolderConditionExpression));

        //            newExpression = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_FolderConditionExpression");
        //            if (newExpression != null)
        //            {
        //                newExpression["DateTimeOperator"].StringValue = folderCondition.DateTimeOperator;
        //                newExpression["FileDateTime"].DateTimeValue = folderCondition.FolderDateTime;
        //                newExpression["Path"].StringValue = folderCondition.Path;
        //            } 
        //            break;

        //        case "SMS_TASKSEQUENCE_FILECONDITIONEXPRESSION":
        //            SMS_TaskSequence_FileConditionExpression fileCondition =
        //               (SMS_TaskSequence_FileConditionExpression)Convert.ChangeType(expression, typeof(SMS_TaskSequence_FileConditionExpression));

        //            newExpression = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_FileConditionExpression");
        //            if (newExpression != null)
        //            {
        //                newExpression["DateTimeOperator"].StringValue = fileCondition.DateTimeOperator;
        //                newExpression["FileDateTime"].DateTimeValue = fileCondition.FileDateTime;
        //                newExpression["Path"].StringValue = fileCondition.Path;

        //                if (string.IsNullOrEmpty(fileCondition.Version))
        //                {
        //                    newExpression["Version"].StringValue = "";
        //                }
        //                else
        //                {
        //                    newExpression["Version"].StringValue = fileCondition.Version;
        //                }
        //                if (string.IsNullOrEmpty(fileCondition.VersionOperator))
        //                {
        //                    newExpression["VersionOperator"].StringValue = "";
        //                }
        //                else
        //                {
        //                    newExpression["VersionOperator"].StringValue = fileCondition.VersionOperator;
        //                }

        //            } 
        //            break;

        //        default:
        //            throw new ArgumentException(Properties.Resources.Error_InvalidParameter, "condition type (" + conditionType + ")");

        //    }
        //    return newExpression;
        //}

        /// <summary>
        /// 
        /// </summary>
        /// <param name="taskSequence"></param>
        public void RecurseTaskSequenceSteps(IResultObject taskSequence)
        {

            try
            {

                List<IResultObject> steps = taskSequence.GetArrayItems("Steps"); //arrayNode of SMS_TaskSequence_Steps

                foreach (IResultObject ro in steps)
                {
                    if (ro["__CLASS"].StringValue == "SMS_TaskSequence_Group")
                    {
                        DialogHelper.ShowMessageBox("Task Sequence Group: " + ro["Name"].StringValue);
                        RecurseTaskSequenceSteps(ro);
                    }
                    else
                    {
                        DialogHelper.ShowMessageBox("Task Sequence Step: " + ro["Name"].StringValue);
                    }
                }
            }
            catch (Exception ex)
            {
                //LogLine(LogFile, "Failed To enumerate task sequence items: " + exceptionInfo.Message);
                IntegrationKitUtilities.LogException(LogFile, ex);

            }

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param taskName="connection"></param>
        /// <param taskName="taskSequence"></param>
        /// <param taskName="groupName"></param>
        /// <param taskName="description"></param>
        /// <param taskName="enabled"></param>
        /// <param taskName="continueOnError"></param>
        /// <returns></returns>
        public static List<IResultObject> AddStepToGroup(ConnectionManagerBase connection, IResultObject taskSequence, string groupName, string description, bool enabled, bool continueOnError)
        {
            try
            {

                List<IResultObject> steps = new List<IResultObject>();
                IResultObject groupObject = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_Group");
                groupObject["Name"].StringValue = groupName;
                groupObject["Description"].StringValue = description;
                groupObject["Enabled"].BooleanValue = enabled;
                groupObject["ContinueOnError"].BooleanValue = continueOnError;

                List<IResultObject> newTaskStepObjects = new List<IResultObject>();
                newTaskStepObjects.Add(taskSequence);

                groupObject.SetArrayItems("Steps", newTaskStepObjects);
                steps.Add(groupObject);
                return steps;
            }
            catch (Exception ex)
            {
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param taskName="connection"></param>
        /// <param taskName="taskSequence"></param>
        /// <param taskName="variableName"></param>
        /// <param taskName="variableValue"></param>
        /// <param taskName="operatorValue"></param>
        /// <returns></returns>
        public static IResultObject InsertCondition(ConnectionManagerBase connection, IResultObject taskSequence, string variableName, string variableValue, string operatorValue)
        {
            try
            {

                IResultObject condition = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_Condition");
                List<IResultObject> conditionItems = new List<IResultObject>();
                IResultObject conditionItem = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_VariableConditionExpression");
                conditionItem["Variable"].StringValue = variableName;
                conditionItem["Operator"].StringValue = operatorValue;
                conditionItem["Value"].StringValue = variableValue;
                conditionItems.Add(conditionItem);

                condition.SetArrayItems("Operands", conditionItems);
                taskSequence.SetSingleItem("Condition", condition);
                return taskSequence;
            }
            catch (Exception ex)
            {
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param taskName="connection"></param>
        /// <param taskName="taskSequence"></param>
        /// <param taskName="query"></param>
        /// <returns></returns>
        public static IResultObject GetWmiConditionObject(ConnectionManagerBase connection, IResultObject taskSequence, string query)
        {
            try
            {

                IResultObject condition = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_Condition");
                List<IResultObject> conditionItems = new List<IResultObject>();
                IResultObject conditionItem = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_WMIConditionExpression");
                conditionItem["Namespace"].StringValue = @"root\cimv2";
                conditionItem["Query"].StringValue = query;
                conditionItems.Add(conditionItem);

                condition.SetArrayItems("Operands", conditionItems);
                taskSequence.SetSingleItem("Condition", condition);
                return taskSequence;
            }
            catch (Exception ex)
            {
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }


        }

        #endregion

        #endregion

        #region Task Sequence Utils

        /// <summary>
        ///     
        /// </summary>
        /// <param name="conn" type="Microsoft.ConfigurationManagement.ManagementProvider.ConnectionManagerBase">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="taskSequence" type="Microsoft.ConfigurationManagement.ManagementProvider.IResultObject">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="wmiClassName" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        ///  /// <param name="nameEndsWith" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A Microsoft.ConfigurationManagement.ManagementProvider.IResultObject value...
        /// </returns>
        public static IResultObject GetTaskStep(ConnectionManagerBase conn, IResultObject taskSequence, string wmiClassName, string nameEndsWith)
        {
            ArgumentNotNull(conn, "connection"); 
            ArgumentNotNull(taskSequence, "taskSequence");
            
            List<IResultObject> stepList = GetFlatTaskSequenceStepList(taskSequence);
            if (stepList == null)
            {
                return null;
            }
            for (int i = 0; i < stepList.Count; i++)
            {
                if (string.Compare(stepList[i]["__CLASS"].StringValue, wmiClassName, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    return stepList[i];
                }
                else if (stepList[i]["__CLASS"].StringValue.EndsWith(nameEndsWith, StringComparison.OrdinalIgnoreCase) == true)
                {
                    return stepList[i];
                }
            }
            return null;
        }

        /// <summary>
        ///     
        /// </summary>
        /// <param name="conn" type="Microsoft.ConfigurationManagement.ManagementProvider.ConnectionManagerBase">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="taskSequence" type="Microsoft.ConfigurationManagement.ManagementProvider.IResultObject">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="wmiClassName" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        ///  /// <param name="nameEndsWith" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A Microsoft.ConfigurationManagement.ManagementProvider.IResultObject value...
        /// </returns>
        public static List<IResultObject> GetTaskStepsOfType(ConnectionManagerBase conn, IResultObject taskSequence, string wmiClassName, string nameEndsWith)
        {
            ArgumentNotNull(conn, "connection");
            ArgumentNotNull(taskSequence, "taskSequence");

            List<IResultObject> foundSteps = new List<IResultObject>();
            List<IResultObject> stepList = GetFlatTaskSequenceStepList(taskSequence);
            if (stepList == null)
            {
                return null;
            }
            for (int i = 0; i < stepList.Count; i++)
            {
                if (string.Compare(stepList[i]["__CLASS"].StringValue, wmiClassName, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    foundSteps.Add(stepList[i]);
                }
                else if (stepList[i]["__CLASS"].StringValue.EndsWith(nameEndsWith, StringComparison.OrdinalIgnoreCase) == true)
                {
                    foundSteps.Add(stepList[i]);
                }
            }
            return foundSteps;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="actionList"></param>
        /// <param name="actionType"></param>
        /// <returns></returns>
        public static bool IsTaskSequenceActionTypeInStepList(List<IResultObject> actionList, string actionType)
        {
            try
            {
                foreach (IResultObject step in actionList)
                {
                    if (string.Compare(step["__CLASS"].StringValue, actionType) == 0)
                    {
                        return true;
                    }
                }
                return false;
            }
            catch (Exception e)
            {
                DialogHelper.ShowMessageBox("Exception occurred while trying to find '" + actionType + "' in the action list.\n" + e.Message);
                throw;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="group"></param>
        /// <returns></returns>
        public static IResultObject CopyTaskSequenceGroup(ConnectionManagerBase conn, IResultObject group)
        {
            try
            {
                IResultObject newGroup = conn.CreateEmbeddedObjectInstance("SMS_TaskSequence_Group");

                newGroup["Name"].StringValue = group["Name"].StringValue;
                newGroup["Description"].StringValue = group["Description"].StringValue;
                newGroup["Enabled"].BooleanValue = true;
                newGroup["ContinueOnError"].BooleanValue = false;

                IResultObject condition;
                if (group["Condition"].ObjectValue != null)
                {
                    condition = group.GetSingleItem("Condition");
                    newGroup.SetSingleItem("Condition", condition);
                }

                return newGroup;
            }
            catch (Exception e)
            {
                DialogHelper.ShowMessageBox("Error Copying the group!\n\n" + e.Message);
                return null;
            }
        }

        /// <summary>
        ///     
        /// </summary>
        /// <param name="group" type="Microsoft.ConfigurationManagement.ManagementProvider.IResultObject">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="deep" type="bool">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A int value...
        /// </returns>
        public static int CountStepsInTaskSequenceGroup(IResultObject group, bool deep)
        {
            try
            {
                int count = 0;

                List<IResultObject> steps = group.GetArrayItems("Steps");

                foreach (IResultObject step in steps)
                {
                    count++;

                    // Child groups that are found. Use recursion to view them (if "deep" is specified).

                    if ((step["__CLASS"].StringValue == "SMS_TaskSequence_Group") && (deep == true))
                    {
                        count = count + CountStepsInTaskSequenceGroup(step, deep);
                    }
                }
                return count;
            }
            catch (SmsException e)
            {
                LogException(LogFile, e);
                throw;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param taskName="connection"></param>
        /// <param taskName="taskSequenceName"></param>
        /// <param taskName="thisNode"></param>
        /// <returns></returns>
        public static IResultObject GetTaskSequenceByName(ConnectionManagerBase connection, string taskSequenceName, bool acceptMultiple)
        {
            IResultObject taskSeqPackages = null;
            string query = string.Empty;
            try
            {
                query = "Select * from SMS_TaskSequencePackage where Name = '" + FixWmiQueryString(taskSequenceName) + "'";
                taskSeqPackages = ExecuteNullableQuery((WqlConnectionManager)connection, query);
                //taskSeqPackages = connection.QueryProcessor.ExecuteQuery(query);
            }
            catch (Exception e)
            {
                DialogHelper.ShowMessageBox(e.Message);
                LogException(LogFile, e, debugEnabled);
                return null;
            }

            if (taskSeqPackages != null)
            {
                int numTS = IntegrationKitUtilities.GetNumberOfChildObjects(taskSeqPackages);
                LogLine(LogFile, "GetTaskSequenceByName: Found (" + numTS + ") task sequences matching the query: " + query, DebugEnabled);

                if (numTS < 1)
                {
                    LogLine(LogFile, "GetTaskSequenceByName: Task sequence not found", DebugEnabled);
                    return null;
                }

                if ((numTS > 1) && (acceptMultiple == false))
                {
                    throw new RankException("More than one task sequence exists by that name but the method parameters specified a requirement to return only one task sequence.");
                }

                if (numTS == 1)
                {

                    foreach (IResultObject taskSeqPackage in taskSeqPackages)
                    {
                        IResultObject taskSequence = GetTaskSequenceFromTSPackage(connection, taskSeqPackage);
                        if ((taskSequence != null)) //&& (IsSelectedTaskSequence(taskSequence, thisNode)))
                        {
                            return taskSequence;
                        }
                        else
                        {
                            LogLine(LogFile, "GetTaskSequenceByName: Null value returned from GetTaskSequenceFromTSPackage", DebugEnabled);
                        }
                    }
                }
                else
                {
                    return taskSeqPackages;
                }

            }
            else
            {
                DialogHelper.ShowMessageBox("Found no task sequences found with the name\n '" + taskSequenceName.Trim() + "'. Try saving the task sequence and re-opening.");
            }
            return null;
            
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param taskName="connection"></param>
        /// <param taskName="taskSequencePackage"></param>
        /// <returns></returns>
        public static IResultObject GetTaskSequenceFromTSPackage(ConnectionManagerBase connection, IResultObject taskSequencePackage)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }
            if (taskSequencePackage == null)
            {
                throw new ArgumentNullException("taskSequencePackage");
            }

            if (string.Compare(taskSequencePackage.ObjectClass, "SMS_TaskSequencePackage", StringComparison.OrdinalIgnoreCase) != 0)
            {
                LogLine(LogFile, "GetTaskSequenceFromTSPackage: A valid SMS_TaskSequencePackage object was not passed in. Object type of 'taskSequencePackage' was " + taskSequencePackage.ObjectClass, DebugEnabled);
                throw new ArgumentException("A valid SMS_TaskSequencePackage object was not passed in. Object type of 'taskSequencePackage' was " + taskSequencePackage.ObjectClass);
            }


            IResultObject taskSequence = null;
            try
            {
                Dictionary<string, object> parameters = new Dictionary<string, object>();
                parameters.Add("TaskSequencePackage", taskSequencePackage);

                string sequenceXmlString = GetROStringProperty(taskSequencePackage, "Sequence");
                if (string.IsNullOrEmpty(sequenceXmlString))
                {
                    LogLine(LogFile, "GetTaskSequenceFromTSPackage: Task sequence package was valid, but it currently has no steps", DebugEnabled);
                    return null;
                }
                IResultObject outParams = connection.ExecuteMethod("SMS_TaskSequencePackage", "GetSequence", parameters);
                if (outParams != null && outParams["ReturnValue"].IntegerValue == 0)
                {
                    taskSequence = outParams.GetSingleItem("TaskSequence");
                    if (taskSequence != null)
                    {
                        LogLine(LogFile, "GetTaskSequenceFromTSPackage: Task sequence found in the task sequence package", DebugEnabled);
                        return taskSequence;
                    }
                    else
                    {
                        LogLine(LogFile, "GetTaskSequenceFromTSPackage: No task sequence found in the task sequence package", DebugEnabled);
                        return null;
                    }
                }
                return null;
                
            }
            catch (Exception e)
            {
                //DialogHelper.ShowMessageBox("Failed to read task sequence package! \n" + e.Message);
                LogLine(LogFile, "GetTaskSequenceFromTSPackage: Exception occurred reading the task sequence package", DebugEnabled);
                LogException(LogFile, e);
                throw;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param taskName="taskSequence"></param>
        /// <param taskName="node"></param>
        /// <returns></returns>
        public static bool IsSelectedTaskSequence(IResultObject taskSequence, SmsTreeNode node)
        {
            try
            {
                SmsTreeNode topNode = null;
                List<SmsTreeNode> nodeList = new List<SmsTreeNode>();
                List<SmsTreeNode> topNodes = new List<SmsTreeNode>();

                string prevNode = string.Empty;
                string nextNode = string.Empty;
                string currentNode = string.Empty;
                if (node != null)
                {
                    currentNode = node.Text;
                    topNode = GetSmsTreeNodeTop(node);
                    while (topNode != null)
                    {
                        topNodes.Add(topNode);
                        topNode = topNode.NextNode;
                    }
                    nodeList = GetFlatSmsTreeNodeList(topNodes);
                }

                int nodeIndex = nodeList.IndexOf(node);
                if (nodeIndex != 0)
                {
                    if (nodeList[nodeIndex - 1] != null)
                    {
                        prevNode = nodeList[nodeIndex - 1].Text;
                    }
                }

                if (nodeIndex != nodeList.Count - 1)
                {
                    if (nodeList[nodeIndex + 1] != null)
                    {
                        nextNode = nodeList[nodeIndex + 1].Text;
                    }
                }


                Nullable<int> stepId = FindStepId(taskSequence, prevNode, currentNode, nextNode);
                if (stepId.HasValue)
                {
                    //RebootStepId = stepId;
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                //DialogHelper.ShowMessageBox("Exception occurred during IsSelectedTaskSequence.\n" + e.Message);
                IntegrationKitUtilities.LogException(LogFile, ex); 
                return false;
            }

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="taskSequencePackage"></param>
        /// <param name="stepTypeFullName"></param>
        /// <param name="stepTypeEndsWith"></param>
        /// <returns></returns>
        public static int? GetNumberOfTaskSequenceStepsOfType(ConnectionManagerBase connection, IResultObject taskSequencePackage, string stepTypeFullName, string stepTypeEndsWith)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }
            if (taskSequencePackage == null)
            {
                throw new ArgumentNullException("taskSequencePackage");
            }

            if (string.IsNullOrEmpty(stepTypeFullName) && string.IsNullOrEmpty(stepTypeEndsWith))
            {
                LogLine(LogFile, "GetNumberOfTaskSequenceStepsOfType: neither of the string values needed for this method were supplied.", DebugEnabled);
                throw new ArgumentException("Neither of the string values needed for this method were supplied.");
            }


            if (string.Compare(taskSequencePackage.ObjectClass, "SMS_TaskSequencePackage", StringComparison.OrdinalIgnoreCase) != 0)
            {
                LogLine(LogFile, "GetNumberOfTaskSequenceStepsOfType: A valid SMS_TaskSequencePackage object was not passed in. Object type of 'taskSequencePackage' was " + taskSequencePackage.ObjectClass, DebugEnabled);
                throw new ArgumentException("A valid SMS_TaskSequencePackage object was not passed in. Object type of 'taskSequencePackage' was " + taskSequencePackage.ObjectClass);
            }

            try
            {
                string sequenceXmlString = IntegrationKitUtilities.GetROStringProperty(taskSequencePackage, "Sequence");
                if (string.IsNullOrEmpty(sequenceXmlString))
                {
                    //LogLine(LogFile, "This is a blank task sequence", DebugEnabled);
                    return 0;
                }

                XmlDocument sequenceXmlDoc = new XmlDocument();
                sequenceXmlDoc.LoadXml(sequenceXmlString);
                
                XmlNodeList stepsFull = null;
                XmlNodeList stepsPartial = null;
                int totalSteps = 0;
                
                //this method tries to find the full matches first, and if no full match is specified/found, it tries the partial matches.
                if (string.IsNullOrEmpty(stepTypeFullName) == false)
                {
                    stepsFull = IntegrationKitUtilities.GetXmlNodeList(sequenceXmlDoc, "//step[@type='" + stepTypeFullName + "']");
                    if (stepsFull != null)
                    {
                        totalSteps = stepsFull.Count;
                    }
                } 
                if ((stepsFull == null) && (string.IsNullOrEmpty(stepTypeEndsWith) == false))
                {
                    //since the "ends-with" function is not available in XPATH 1.0, we have to do some tricky logic to accomplish the same thing.
                    // > substring-before(@type, 'var')   should return all steps that contain this word/phrase
                    stepsPartial = IntegrationKitUtilities.GetXmlNodeList(sequenceXmlDoc, "//step[contains(@type, '" + stepTypeEndsWith + "')]");

                    if (stepsPartial != null)
                    {
                        //found some nodes that contain this word/phrase. Now check each one to see if it is really a match (ends with the word/phrase)
                        foreach (XmlNode step in stepsPartial)
                        {
                            string stepType = IntegrationKitUtilities.GetXmlAttribute(step, "type");
                            if ((string.IsNullOrEmpty(stepType) == false) && (stepType.EndsWith(stepTypeEndsWith, StringComparison.OrdinalIgnoreCase)))
                            {
                                totalSteps++;
                            }
                        }
                    }
                } 
                return totalSteps;
            }
            catch (Exception e)
            {
                IntegrationKitUtilities.LogException(LogFile, e);
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param taskName="node"></param>
        /// <returns></returns>
        public static SmsTreeNode GetSmsTreeNodeTop(SmsTreeNode node)
        {
            try
            {
                if (node.Level > 0)
                {
                    node = GetSmsTreeNodeRoot(node);
                }
                while (node.PrevNode != null)
                {
                    node = node.PrevNode;
                }
                return node;
            }
            catch (Exception ex)
            {
                IntegrationKitUtilities.LogException(LogFile, ex); 
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param taskName="nodes"></param>
        /// <returns></returns>
        public static List<SmsTreeNode> GetFlatSmsTreeNodeList(List<SmsTreeNode> nodes)
        {
            try
            {
                List<SmsTreeNode> nodeList = new List<SmsTreeNode>();

                for (int i = 0; i < nodes.Count; i++)
                {
                    if (nodes[i].GetNodeCount(true) > 0)
                    {
                        List<SmsTreeNode> nodeChildren = new List<SmsTreeNode>();
                        nodeList.Add(nodes[i]);
                        foreach (SmsTreeNode node in nodes[i].Nodes)
                        {
                            nodeChildren.Add(node);
                        }
                        nodeList.AddRange(GetFlatSmsTreeNodeList(nodeChildren));
                    }
                    else
                    {
                        nodeList.Add(nodes[i]);
                    }
                }

                

                return nodeList;
            }
            catch (SmsException ex)
            {
                LogLine(LogFile, "Failed To enumerate node list: " + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null; 
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param taskName="node"></param>
        /// <returns></returns>
        public static SmsTreeNode GetSmsTreeNodeRoot(SmsTreeNode node)
        {
            try
            {
                if (node.Level > 0)
                {
                    return GetSmsTreeNodeRoot(node.Parent);
                }
                else
                {
                    return node;
                }

            }
            catch (Exception e)
            {
                DialogHelper.ShowMessageBox("Exception error during GetSmsTreeNodeRoot\n\n" + e.Message);
                IntegrationKitUtilities.LogException(LogFile, e);
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param taskName="taskSequence"></param>
        /// <param taskName="previousStep"></param>
        /// <param taskName="currentStep"></param>
        /// <param taskName="nextStep"></param>
        /// <returns></returns>
        public static Nullable<int> FindStepId(IResultObject taskSequence, string previousStep, string currentStep, string nextStep)
        {
            try
            {
                bool prevMatch = false;
                bool currentMatch = false;
                bool nextMatch = false;

                List<IResultObject> flatStepList = GetFlatTaskSequenceStepList(taskSequence);

                IResultObject stepObj = null;
                IResultObject prevStepObj = null;
                IResultObject nextStepObj = null;

                //TotalSteps = flatStepList.Count;

                for (int i = 0; i < flatStepList.Count; i++)
                {
                    stepObj = flatStepList[i];
                    if (string.Compare(currentStep, stepObj["Name"].StringValue, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        if (i == 0)
                        {
                            DialogHelper.ShowMessageBox("The 'Reboot To PXE' step is the first step in the task sequence.\n\nThis action serves no purpose as the first action in a task sequence. Either move or delete this action.");
                            return null;
                        }
                        else if ((i > 0) && (i == (flatStepList.Count - 1)))
                        {
                            DialogHelper.ShowMessageBox("The 'Reboot To PXE' step is the last step in the task sequence.\n\nThis action serves no purpose as the last action in a task sequence. Either move or delete this action.");
                            return null;
                        }
                        else
                        {
                            currentMatch = true;

                            if (i > 0)
                            {
                                prevStepObj = flatStepList[i - 1];
                                if (previousStep == null)
                                {
                                    if (string.Compare("SMS_TaskSequence_Group", prevStepObj["__CLASS"].StringValue, StringComparison.OrdinalIgnoreCase) == 0)
                                    {
                                        prevMatch = true;
                                    }
                                    else
                                    {
                                        prevMatch = false;
                                    }
                                }
                                else if (string.Compare(previousStep, prevStepObj["Name"].StringValue, StringComparison.OrdinalIgnoreCase) == 0)
                                {
                                    prevMatch = true;
                                }
                                else
                                {
                                    prevMatch = false;
                                }
                            }

                            if (i < flatStepList.Count - 1)
                            {
                                nextStepObj = flatStepList[i + 1];
                                if (nextStep == null)
                                {
                                    if (string.Compare("SMS_TaskSequence_Group", nextStepObj["__CLASS"].StringValue, StringComparison.OrdinalIgnoreCase) == 0)
                                    {
                                        nextMatch = true;
                                    }
                                    else
                                    {
                                        nextMatch = false;
                                    }
                                }
                                else if (string.Compare(nextStep, nextStepObj["Name"].StringValue, StringComparison.OrdinalIgnoreCase) == 0)
                                {
                                    nextMatch = true;
                                }
                                else
                                {
                                    nextMatch = false;
                                }
                            }
                        }
                        if ((currentMatch == true) && (prevMatch == true) && (nextMatch == true))
                        {
                            //RebootNodeObj = stepObj;
                            return i;
                        }
                    }
                }

                DialogHelper.ShowMessageBox("Could not verify the task sequence being edited.\n\nPlease save the task sequence first, close and re-open the editor and select \"Reboot to PXE\" again.");
                return null;

            }
            catch (SmsException ex)
            {
                LogLine(LogFile, "Exception occurred while enumerating the task sequence: " + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        /// Compares all of the steps (title text) of a task sequence from a package against a tree node to see if they are the same.
        /// </summary>
        /// <param name="taskSequencePackage"></param>
        /// <param name="node"></param>
        /// <returns></returns>
        public static bool TaskSequencesAreEqual(IResultObject taskSequencePackage, SmsTreeNode node)
        {
            ArgumentNotNull(taskSequencePackage, "taskSequence");
            ArgumentNotNull(node, "node");

            try
            {
                //modified 2/6/09 by rhearn to fix issue where removing current step was not appropriate 
                //  (in the case where the user is not adding a new step but needs this comparison anyway)
                //  Now the code will compare the list length first, and if the XML list == treeNode list + 1, *then*
                //  the current node will be removed and the list checked against the XML

                List<SmsTreeNode> treeNodeList = new List<SmsTreeNode>();
                List<SmsTreeNode> topNodes = new List<SmsTreeNode>();

               
                //create a list of node titles, flattening out the node tree
                SmsTreeNode topNode = GetSmsTreeNodeTop(node);
                while (topNode != null)
                {
                    topNodes.Add(topNode);
                    topNode = topNode.NextNode;
                }
                treeNodeList = GetFlatSmsTreeNodeList(topNodes);
                
                //now remove groups and the item that is being added to the treeview so the compare will work against the saved XML sequence
                for (int i = 0; i < treeNodeList.Count; i++)
                {
                    if (treeNodeList[i].IsContainer == true)
                    {
                        treeNodeList.Remove(treeNodeList[i]);
                        i--;
                    }
                }

                //create a flat nodelist of all steps in the task sequence XML               
                string sequenceXmlString = IntegrationKitUtilities.GetROStringProperty(taskSequencePackage, "Sequence");
                if (string.IsNullOrEmpty(sequenceXmlString))
                    return false;

                XmlDocument sequenceXmlDoc = new XmlDocument();
                sequenceXmlDoc.LoadXml(sequenceXmlString);
                XmlNodeList xmlNodes = GetXmlNodeList(sequenceXmlDoc, "//step");
                //modified 2/5/09 by rhearn to fix issue #3747
                if (xmlNodes == null)
                {
                    //the task sequence "object" has no steps (not saved yet)

                    //modified 5/12/09 by rhearn to fix issue 4319.
                    // The issue here is that when adding a new step to the task sequence, a new node is created in the tree view
                    // and the node count would never be zero if the new node is added before this code runs.
                    // Modified to change the comparison to where the count is 1, because if the saved TS is null, and there is only one 
                    // tree node, and this code is running, then it must be our task sequence.
                    
                    //if (treeNodeList.Count == 0)
                    if (treeNodeList.Count == 1)
                    {
                        //if there are also no nodes in the tree (in the UI), then continue.
                        return true;
                    }
                    else
                    {
                        // There are nodes in the tree. Force the user to save the TS first.
                        return false;
                    }
                }

                if (treeNodeList.Count != xmlNodes.Count)
                {
                    // If the two lists don't have the same number of items, it can't be the same task sequence.
                    // However, if the tree list has one more item than the XML list, it could be that the
                    //  user is adding a new step. Try removing the step from the tree and compare...
                    if ((treeNodeList.Count - 1) == xmlNodes.Count)
                    {
                        treeNodeList.Remove(node);
                    }
                    else
                    {
                        return false;
                    }
                }

                for (int i = 0; i < treeNodeList.Count; i++)
                {
                    SmsTreeNode treeNode = treeNodeList[i];
                    XmlNode xNode = xmlNodes[i];
                    string xmlNodeName = GetXmlAttribute(xmlNodes[i], "name");
                    if ((string.IsNullOrEmpty(xmlNodeName) == false) &&
                        (string.Compare(xmlNodeName, treeNode.Text, StringComparison.CurrentCultureIgnoreCase) != 0))
                    {
                        //the node titles are not equal. Go ahead and return false without further testing.
                        return false;
                    }
                }

                //if the code reached this point, it went through the entire list without failing a comparison.
                return true;
                
            }
            catch (Exception ex)
            {
                //DialogHelper.ShowMessageBox("Exception occurred during IsSelectedTaskSequence.\n" + e.Message);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return false;
            }

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param taskName="taskSequence"></param>
        /// <returns></returns>
        public static List<IResultObject> GetFlatTaskSequenceStepList(IResultObject taskSequence)
        {
            try
            {
                List<IResultObject> stepList = new List<IResultObject>();

                List<IResultObject> steps = taskSequence.GetArrayItems("Steps");

                foreach (IResultObject ro in steps)
                {
                    // Child groups that are found. Use recursion to view them.
                    if (string.Compare("SMS_TaskSequence_Group", ro["__CLASS"].StringValue, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        stepList.Add(ro);
                        stepList.AddRange(GetFlatTaskSequenceStepList(ro));
                    }
                    else
                    {
                        stepList.Add(ro);
                    }
                }
                return stepList;
            }
            catch (SmsException ex)
            {
                LogLine(LogFile, "Failed To enumerate task sequence items: " + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param taskName="taskSequence"></param>
        /// <param taskName="node"></param>
        /// <returns></returns>
        public static int GetCurrentStepNumber(SmsTreeNode node)
        {
            try
            {
                SmsTreeNode topNode = null;
                List<SmsTreeNode> nodeList = new List<SmsTreeNode>();
                List<SmsTreeNode> topNodes = new List<SmsTreeNode>();

                if (node != null)
                {
                    topNode = GetSmsTreeNodeTop(node);
                    while (topNode != null)
                    {
                        topNodes.Add(topNode);
                        topNode = topNode.NextNode;
                    }
                    nodeList = GetFlatSmsTreeNodeList(topNodes);
                }

                return nodeList.IndexOf(node);

            }
            catch (Exception e)
            {
                DialogHelper.ShowMessageBox("Exception occurred during GetCurrentStepNumber.\n" + e.Message);
                IntegrationKitUtilities.LogException(LogFile, e); 
                return -1;
            }
        }


        #endregion
 
        #region OS Image / Boot Image Packages

        
        //public string GetBootImageOsVersion(WqlConnectionManager connection, string bootImageName)
        //{

        //    if (connection == null)
        //    {
        //        throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "connection");
        //    }
        //    if (string.IsNullOrEmpty(bootImageName))
        //    {
        //        throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "bootImageName");
        //    }

        //    try
        //    {
        //        string bootImageOsVersion = string.Empty;

        //        IResultObject bootImagePackage = null;
        //        IResultObject bootImagePackages = GetPackageByName(connection, bootImageName, PackageType.BootImagePackage, null);
        //        if (bootImagePackages != null)
        //        {
        //            foreach (IResultObject obj in bootImagePackages)
        //            {
        //                bootImagePackage = obj;
        //                break;
        //            }
        //        }
        //        if (bootImagePackage != null)
        //        {
        //            string packageID = IntegrationKitUtilities.GetROStringProperty(bootImagePackage, "PackageID");
        //            if (string.IsNullOrEmpty(packageID) == false)
        //            {
        //                bootImageOsVersion = GetBootImageOsVersion(connection, packageID);
        //            }
        //        }
                
        //        return bootImageOsVersion;
        //    }
        //    catch (Exception ex)
        //    {
        //        LogLine(LogFile, "Exception occurred in GetBootImagePackage(). Error: " + ex.Message + "\n" + ex.Details + "\n" + ex.Data + "\n" + ex.InnerException);
        //        IntegrationKitUtilities.LogException(LogFile, ex);
        //        return null;
        //    }
            
        //}

        /// <summary>
        ///     
        /// </summary>
        /// <param name="connection" type="Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine.WqlConnectionManager">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="imagePackageId" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A string value...
        /// </returns>
        public static string GetBootImageOsVersion(WqlConnectionManager connection, string imagePackageId)
        {
            //notes: OS Version is stored in XML format along with other information in a single property in the
            //       boot image package object. This method extracts the XML and selects that property and returns a string.
            //       Here is the format of the XML in the property:
            //       <WIM>
            //          <IMAGE name="Microsoft Windows Vista PE (x86)" index="1">
            //            <Property name="OS version" readonly="true">6.0.6001.18000</Property>
            //            <Property name="Architecture" readonly="true">0</Property>
            //            <Property name="Creation date" readonly="true">20080123180336.597000+000</Property>
            //            <Property name="Language" readonly="true">en-US</Property>
            //            <Property name="HAL" readonly="true"></Property>
            //            <Property name="Size" readonly="true">325563607</Property>
            //            <Property name="Image description" readonly="false">Microsoft Windows Vista PE (x86)</Property>
            //            <Property name="Created by" readonly="false"></Property>
            //            <Property name="Image version" readonly="false"></Property>
            //          </IMAGE>
            //       </WIM>
            //
            if (connection == null)
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "connection");
            }
            if (string.IsNullOrEmpty(imagePackageId))
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "imagePackageId");
            }

            try
            {
                string bootImageOsVersion = string.Empty;
                string bootImageProperty = string.Empty;
                XmlDocument bootImageXml = new XmlDocument();

                IResultObject bootImagePackage = null;
                bootImagePackage = connection.GetInstance(@"SMS_BootImagePackage.PackageID='" + imagePackageId + "'");

                if (bootImagePackage != null)
                {
                    bootImageProperty = GetROStringProperty(bootImagePackage, "ImageProperty");
                    if (string.IsNullOrEmpty(bootImageProperty) == false)
                    {
                        bootImageXml.LoadXml(bootImageProperty);
                        bootImageOsVersion = GetXmlNodeValue(bootImageXml, "//Property[@name='OS version']");
                    }
                }
                return bootImageOsVersion;
            }
            catch (Exception ex)
            {
                LogLine(LogFile, "Exception occurred in GetBootImagePackage(). Error: " + ex.Message + "\n" + ex.Data.ToString() + "\n" + ex.InnerException, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
            
        }

        /// <summary>
        ///     
        /// </summary>
        /// <param name="connection" type="Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine.WqlConnectionManager">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="imagePath" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A string value...
        /// </returns>
        public static string GetBootImagePackageIdFromImagePath(WqlConnectionManager connection, string imagePath)
        {
            if (connection == null)
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "connection");
            }

            if (string.IsNullOrEmpty(imagePath))
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "imagePath");
            }
            

            try
            {
                if (File.Exists(imagePath) == false)
                {
                    LogLine(LogFile, "WIM File does not exist: " + imagePath, DebugEnabled);
                    return string.Empty;
                }

                string packageID = string.Empty;

                //need to modify the imagePath so that any '\' is changed to '\\' for the WQL query.
                imagePath = imagePath.Replace("\\", "\\\\");

                string query = "Select * from SMS_BootImagePackage Where ImagePath='" + imagePath + "'";
                LogLine(LogFile, "Query for boot image package: " + query, DebugEnabled);
                    
                IResultObject bootImagePackage = ExecuteNullableQuery(connection, query);
                if (bootImagePackage != null)
                {
                    LogLine(LogFile, "Found a boot image package matching the criteria", DebugEnabled);
                    foreach (IResultObject obj in bootImagePackage)
                    {
                        LogLine(LogFile, "Boot image name: " + GetROStringProperty(obj, "Name"), DebugEnabled);
                        packageID = GetROStringProperty(obj, "PackageID");
                        LogLine(LogFile, "PackageID = " + packageID, DebugEnabled); 
                        break;
                    }
                    
                    
                }
                return packageID;
            }
            catch (Exception ex)
            {
                LogLine(LogFile, "Exception occured in GetDriverByPathAndFile().\n" + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }


        }

        /// <summary>
        ///     
        /// </summary>
        /// <param name="connection" type="Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine.WqlConnectionManager">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="bootImageName" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A Microsoft.ConfigurationManagement.ManagementProvider.IResultObject value...
        /// </returns>
        public static IResultObject CreateNewBootImage(WqlConnectionManager connection, string bootImageName)
        {
             if (connection == null)
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "connection");
            }
            if (string.IsNullOrEmpty(bootImageName))
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "name");
            }


            try
            {
                IResultObject bootImagePackage = null;
                // first check and see if there is a duplicate package = if so, use that one and update it
                IResultObject bootImagePackages = GetPackageByName(connection, bootImageName, PackageType.BootImagePackage, null);
                if (bootImagePackages != null)
                {
                    foreach (IResultObject obj in bootImagePackages)
                    {
                        bootImagePackage = obj;
                        break;
                    }
                }
                if (bootImagePackage != null)
                {
                    string newPackageID = IntegrationKitUtilities.GetROStringProperty(bootImagePackage, "PackageID");
                    if (string.IsNullOrEmpty(newPackageID) == false)
                    {
                        LogLine(LogFile, "Existing package will be updated.", DebugEnabled);
                        bootImagePackage = connection.GetInstance(@"SMS_BootImagePackage.PackageID='" + newPackageID + "'");
                    }
                }

                if (bootImagePackage == null)
                {

                    // Create new package object.
                    bootImagePackage = connection.CreateInstance("SMS_BootImagePackage");
                    if (bootImagePackage == null)
                    {
                        LogLine(LogFile, "new package object was null after CreateInstance.", DebugEnabled);
                        return null;
                    }
                    LogLine(LogFile, "New package object instance created.", DebugEnabled);
                }
                return bootImagePackage;
            }
            catch (Exception ex)
            {
                LogLine(LogFile, "Failed to create package. Error: " + ex.Message + "\n" + ex.Data + "\n" + ex.InnerException, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        /// /
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="bootImageName"></param>
        /// <param name="description"></param>
        /// <param name="pathToWim"></param>
        /// <returns></returns>
        public static IResultObject ImportBootWim(WqlConnectionManager connection, string bootImageName, string description, string pathToWim)
        {
            if (connection == null)
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "connection");
            }
            if (string.IsNullOrEmpty(bootImageName))
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "name");
            }
            if (string.IsNullOrEmpty(pathToWim))
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "pathToWim");
            }
            
            
            try
            {
                IResultObject bootImagePackage = null;
                // first check and see if there is a duplicate package = if so, use that one and update it
                IResultObject bootImagePackages = GetPackageByName(connection, bootImageName, PackageType.BootImagePackage, null);
                if (bootImagePackages != null)
                {
                    foreach (IResultObject obj in bootImagePackages)
                    {
                        bootImagePackage = obj;
                        break;
                    }
                }
                if (bootImagePackage != null)
                {
                    string newPackageID = IntegrationKitUtilities.GetROStringProperty(bootImagePackage, "PackageID");
                    if (string.IsNullOrEmpty(newPackageID) == false)
                    {
                        LogLine(LogFile, "Existing package will be updated.", DebugEnabled);
                        bootImagePackage = connection.GetInstance(@"SMS_BootImagePackage.PackageID='" + newPackageID + "'");
                    }
                }
                
                if (bootImagePackage == null)
                {

                    // Create new package object.
                    bootImagePackage = connection.CreateInstance("SMS_BootImagePackage");
                    if (bootImagePackage == null)
                    {
                        LogLine(LogFile, "new package object was null after CreateInstance.", DebugEnabled);
                        return null;
                    }
                    LogLine(LogFile, "New package object instance created.", DebugEnabled);
                }
                LogLine(LogFile, "Created an instance of SMS_BootImagePackage", DebugEnabled);
                
                // Populate new boot image package properties.
                bootImagePackage["Name"].StringValue = bootImageName;
                bootImagePackage["Description"].StringValue = description;
                bootImagePackage["ImagePath"].StringValue = pathToWim; // UNC path required.
                bootImagePackage["ImageIndex"].IntegerValue = 1; // Index into WIM file for image.
                bootImagePackage["PkgSourceFlag"].IntegerValue = 2; // 
                bootImagePackage["PackageType"].IntegerValue = 258; // boot image

                // Save new package and new package properties.
                bootImagePackage.AutoCommit = true;
                bootImagePackage.Put();
                bootImagePackage.AutoRefresh = true;
                //bootImagePackage.Get();
                return bootImagePackage;
            }
            catch (Exception ex)
            {
                LogLine(LogFile, "Failed to create package. Error: " + ex.Message + "\n" + ex.Data + "\n" + ex.InnerException, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="exportImagePath"></param>
        /// <param name="imageIndex"></param>
        /// <param name="architecture"></param>
        /// <returns></returns>
        public static FileInfo ExportBootWimFromWaik(WqlConnectionManager connection, string exportImagePath, int imageIndex, string architecture)
        {
            //
            // TO DO: This method fails with a "Not Found" exception. Perhaps this is due to WAIK, but not known. Need to research.
            //
            //
            //
            //
            //
            //
            // 
            
            if (connection == null)
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "connection");
            }
            if (string.IsNullOrEmpty(exportImagePath))
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "exportImagePath");
            }
            
            try
            {
                
                if (imageIndex < 1)
                {
                    imageIndex = 1;
                }
                if (string.IsNullOrEmpty(architecture))
                {
                    architecture = "x86";  //default to x86 if left blank
                }
                else if ((string.Compare(architecture, "x86", StringComparison.OrdinalIgnoreCase) != 0) &&
                    (string.Compare(architecture, "x64", StringComparison.OrdinalIgnoreCase) != 0) &&
                    (string.Compare(architecture, "ia64", StringComparison.OrdinalIgnoreCase) != 0))
                {
                    // architectre string was invalid
                    throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "architecture");
                }
                
                //get the path of the directory containing the Wim file to be created
                string pathName = exportImagePath.Substring(0, (exportImagePath.LastIndexOf(@"\")));
                DirectoryInfo di = new DirectoryInfo(pathName);
                if (di == null)
                {
                    di = Directory.CreateDirectory(pathName);
                    if (di == null)
                    {
                        //could not find directory, could not create directory
                        return null;
                    }
                }

                LogLine(LogFile, "Directory for WIM file: " + di.FullName, DebugEnabled);

                Dictionary<string, object> inParams = new Dictionary<string, object>();

                // Set up parameters for the WMI method
                inParams.Add("Architecture", architecture);
                inParams.Add("ImageIndex", imageIndex);
                inParams.Add("ExportImagePath", di.FullName);

                LogLine(LogFile, "Architecture:    " + architecture, DebugEnabled);
                LogLine(LogFile, "ImageIndex:      " + imageIndex, DebugEnabled);
                LogLine(LogFile, "ExportImagePath: " + di.FullName, DebugEnabled);

                // Import the INF file.
                IResultObject result = connection.ExecuteMethod("SMS_BootImage", "ExportDefaultBootImage", inParams);
                if (result == null)
                {
                    LogLine(LogFile, "Error occurred when exporting boot image", DebugEnabled);
                    return null;
                }

                if (File.Exists(exportImagePath) == false)
                {
                    LogLine(LogFile, "Error occurred when exporting boot image. File not found: " + exportImagePath, DebugEnabled);
                    return null;
                }

                FileInfo fi = new FileInfo(exportImagePath);
                if (fi == null)
                {
                    LogLine(LogFile, "Error getting FileInfo data on WIM file: " + exportImagePath, DebugEnabled);
                    return null;
                }
                return fi;
            }
            catch (SmsQueryException ex)
            {
                LogLine(LogFile, "Failed to export the boot image. Error: " + ex.Message + "\n" + ex.Details + "\n" + ex.Data + "\n" + ex.InnerException, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
            catch (SmsException ex)
            {
                LogLine(LogFile, "Failed to export the boot image. Error: " + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }





        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="imagePackageId"></param>
        /// <returns></returns>
        public static int RefreshImagePackage(WqlConnectionManager connection, string imagePackageId)
        {
            if (connection == null)
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "connection");
            }
            if (string.IsNullOrEmpty(imagePackageId))
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "imagePackageId");
            }

            try
            {
                IResultObject imagePackage = connection.GetInstance(@"SMS_ImagePackage.PackageID='" + imagePackageId + "'");
                imagePackage.AutoCommit = true;
                imagePackage.Put();
                imagePackage.ExecuteMethod("RefreshPkgSource", null);
                return 0;
            }
            catch (SmsException ex)
            {
                LogLine(LogFile, "Exception during RefreshImagePackage(): " + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return 1;
            }
        }

        
        #endregion

        #region Driver Management

        //Drivers

        /// <summary>
        ///     
        /// </summary>
        /// <param name="connection" type="Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine.WqlConnectionManager">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="path" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="name" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="driverName" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A Microsoft.ConfigurationManagement.ManagementProvider.IResultObject value...
        /// </returns>
        public static IResultObject ImportInfDriver(WqlConnectionManager connection, string path, string name, string driverName)
        {
            try
            {
                if (string.IsNullOrEmpty(path))
                {
                    throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "path");
                }
                if (string.IsNullOrEmpty(name))
                {
                    throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "name");
                }
                if (connection == null)
                {
                    throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "connection");
                }
                if (File.Exists(path + @"\" + name) == false)
                {
                    throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter + " " + path + @"\" + name, "path\\name");
                }
                LogLine(LogFile, "Now in ImportInfDriver():", DebugEnabled);

                Dictionary<string, object> inParams = new Dictionary<string, object>();

                // Set up parameters for the path and file name.
                inParams.Add("DriverPath", path);
                inParams.Add("INFFile", name);
                IResultObject result = null;
                IResultObject driver = null;

                //Check to see if the driver already exists, and if so, use that one.
                
                //modified 2/3/09 by rhearn to fix issues where correct matching driver was not getting returned
                FileInfo infFileinfo = new FileInfo(path + @"\" + name);
                if (infFileinfo == null)
                {
                    LogLine(LogFile, "Could not get INF file info. Cannot continue", DebugEnabled);
                    return null;
                }

                driver = GetMatchingDriver(connection, infFileinfo);
                //driver = GetDriverByPathAndFile(connection, path, name);

                if (driver == null)
                {
                    try
                    {
                        // Import the INF file.
                        result = connection.ExecuteMethod("SMS_Driver", "CreateFromINF", inParams);
                        if (result == null)
                        {
                            LogLine(LogFile, "Error occurred during CreateFromINF", DebugEnabled);
                            return null;
                        }

                        driver = connection.CreateInstance(result["Driver"].ObjectValue);
                        if (driver == null)
                        {
                            LogLine(LogFile, "Error occurred during CreateInstance(result[\"Driver\".ObjectValue", DebugEnabled);
                            return null;
                        }
                    }
                    catch (SmsQueryException qex)
                    {
                        result = null;
                        long statusCode = qex.ExtendStatusErrorCode;
                        if (statusCode == 13)
                        {
                            LogLine(LogFile, "The driver specified was invalid", DebugEnabled);
                        }
                        if (statusCode == 1633)
                        {
                            LogLine(LogFile, "The driver does not support any platforms supported by Configuration Manager", DebugEnabled);
                        }
                        if (statusCode == 2)
                        {
                            LogLine(LogFile, "The SMS Provider cannot access the network share", DebugEnabled);
                        } 
                        if (statusCode == 183)
                        {
                            LogLine(LogFile, "Driver already exists...but could not retrieve the existing driver. Trying again to get a driver to return.", DebugEnabled);
                            string query = "Select * From SMS_Driver Where DriverINFFile='" + name + "'";
                            LogLine(LogFile, "Running query: " + query, DebugEnabled);

                            IResultObject drivers = ExecuteNullableQuery(connection, query);
                            if (drivers != null)
                            {
                                LogLine(LogFile, "Query returned an object: " + drivers.GetType().FullName, DebugEnabled);
                                foreach (IResultObject obj in drivers)
                                {
                                    // modified 5/13/09 by rhearn - related to issue 4390
                                    //  This code should not override the .CAT file hashing and simply return the first driver found.
                                    //  This would lead to incorrectly identifying a driver as a match, which is worse than simply failing.
                                    //return obj;
                                    LogLine(LogFile, "Potential matching driver: " + IntegrationKitUtilities.GetROStringProperty(obj, "LocalizedDisplayName"), DebugEnabled);
                                }
                            }
                            
                        }
                        return null;
                    }
                }
                // Enable the driver.
                driver["IsEnabled"].BooleanValue = true;

                List<IResultObject> driverInformationList = driver.GetArrayItems("LocalizedInformation");

                // Set up the display name and other information.
                IResultObject driverInfo = connection.CreateEmbeddedObjectInstance("SMS_CI_LocalizedProperties");

                LogLine(LogFile, "Calling GetDriverName()", DebugEnabled);
                //===[ begin modification ]==================================
                // Modified 9/16/08 by rhearn
                // - added a new code to create driver name as specified in the XML
                if (string.IsNullOrEmpty(driverName) == false)
                {
                    driverInfo["DisplayName"].StringValue = driverName;
                }
                else
                {
                    driverInfo["DisplayName"].StringValue = GetDriverName(driver);
                }
                //driverInfo["DisplayName"].StringValue = GetDriverName(driver);
                //===[ end modification ]==================================
                driverInfo["LocaleID"].IntegerValue = 1033;
                driverInfo["Description"].StringValue = "";

                LogLine(LogFile, "DisplayName" + driverInfo["DisplayName"].StringValue, DebugEnabled);

                driverInformationList.Add(driverInfo);

                driver.SetArrayItems("LocalizedInformation", driverInformationList);

                LogLine(LogFile, "Saving changes to driver", DebugEnabled);

                // Commit the SMS_Driver object.
                driver.AutoCommit = true;
                driver.Put();
                driver.Get();

                return driver;

            }
            catch (SmsQueryException qex)
            {
                LogLine(LogFile, "Exception occurred in ImportInfDriver() : " + qex.ExtendStatusErrorCode + "\n" + qex.Details + "\n" + qex.Data + "\n" + qex.TargetSite + "\n" + qex.InnerException + "\n" + qex.Message + "\n" + qex.StackTrace, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, qex);
                return null;
            }
            catch (Exception ex)
            {
                LogLine(LogFile, "Exception occured in ImportInfDriver().\n" + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        ///     
        /// </summary>
        /// <param name="connection" type="Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine.WqlConnectionManager">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="path" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="name" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="driverName" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A Microsoft.ConfigurationManagement.ManagementProvider.IResultObject value...
        /// </returns>
        public static IResultObject ImportOemDriver(WqlConnectionManager connection, string path, string name, string driverName)
        {
            try
            {
                if (string.IsNullOrEmpty(path))
                {
                    throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "path");
                }
                if (string.IsNullOrEmpty(name))
                {
                    throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "name");
                }
                if (connection == null)
                {
                    throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "connection");
                }
                if (File.Exists(path + @"\" + name) == false)
                {
                    throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter + " " + path + @"\" + name, "path\\name");
                }
                LogLine(LogFile, "Now in ImportOemDriver()", DebugEnabled);
                
                Dictionary<string, object> inParams = new Dictionary<string, object>();

                // Set up parameters for the path and file name.
                inParams.Add("DriverPath", path);
                inParams.Add("OEMFile", name);
                IResultObject result = null;
                IResultObject driver = null;

                //modified 2/3/09 by rhearn to fix issues where correct matching driver was not getting returned
                FileInfo infFileinfo = new FileInfo(path + @"\" + name);
                if (infFileinfo == null)
                {
                    LogLine(LogFile, "Could not get OEM file info. Cannot continue", DebugEnabled);
                    return null;
                }

                driver = GetMatchingDriver(connection, infFileinfo); 
                //driver = GetDriverByPathAndFile(connection, path, name);
                if (driver == null)
                {
                    LogLine(LogFile, "GetDriverByPathAndFile returned null", DebugEnabled);
                            
                    try
                    {
                        // Import the OEM file - SCCM returns a drivers *array*.
                        result = connection.ExecuteMethod("SMS_Driver", "CreateFromOEM", inParams);
                        if (result == null)
                        {
                            LogLine(LogFile, "Error occurred during CreateFromOEM", DebugEnabled);
                            return null;
                        }
                        LogLine(LogFile, "CreateFromOem returned an object: " + result.GetType().FullName, DebugEnabled);
                                
                        foreach (object obj in result["Drivers"].ObjectArrayValue)
                        {
                            LogLine(LogFile, "Processing a driver", DebugEnabled);
                        
                            driver = connection.CreateInstance(obj);
                            if (driver == null)
                            {
                                LogLine(LogFile, "Error occurred during CreateInstance(result[\"Driver\"].ObjectValue", DebugEnabled);
                                return null;
                            }

                            LogLine(LogFile, "CreateInstance returned an object: " + driver.GetType().FullName, DebugEnabled);
                            LogLine(LogFile, "Now setting driver properties", DebugEnabled);
                        
                            // Enable the driver.
                            driver["IsEnabled"].BooleanValue = true;

                            List<IResultObject> driverInformationList = driver.GetArrayItems("LocalizedInformation");

                            // Set up the display name and other information.
                            IResultObject driverInfo = connection.CreateEmbeddedObjectInstance("SMS_CI_LocalizedProperties");

                            LogLine(LogFile, "Calling GetDriverName()", DebugEnabled);

                            //===[ begin modification ]==================================
                            // Modified 9/16/08 by rhearn
                            // - added a new code to create driver name as specified in the XML
                            if (string.IsNullOrEmpty(driverName) == false)
                            {
                                driverInfo["DisplayName"].StringValue = driverName;
                            }
                            else
                            {
                                driverInfo["DisplayName"].StringValue = GetDriverName(driver);
                            }
                            //driverInfo["DisplayName"].StringValue = GetDriverName(driver);
                            //===[ end modification ]==================================
                            driverInfo["LocaleID"].IntegerValue = 1033;
                            driverInfo["Description"].StringValue = "";

                            LogLine(LogFile, "DisplayName" + driverInfo["DisplayName"].StringValue, DebugEnabled);

                            driverInformationList.Add(driverInfo);

                            driver.SetArrayItems("LocalizedInformation", driverInformationList);

                            LogLine(LogFile, "Saving changes to driver", DebugEnabled);

                            // Commit the SMS_Driver object.
                            driver.AutoCommit = true;
                            driver.Put();
                            driver.Get();

                            return driver;
                        }
                    }
                    catch (SmsQueryException qex)
                    {
                        result = null;
                        long statusCode = qex.ExtendStatusErrorCode;
                        if (statusCode == 13)
                        {
                            LogLine(LogFile, "The driver specified was invalid", DebugEnabled);
                        }
                        if (statusCode == 1633)
                        {
                            LogLine(LogFile, "The driver does not support any platforms supported by Configuration Manager", DebugEnabled);
                        }
                        if (statusCode == 2)
                        {
                            LogLine(LogFile, "The SMS Provider cannot access the network share", DebugEnabled);
                        }
                        if (statusCode == 183)
                        {
                            LogLine(LogFile, "Driver already exists...but could not retrieve the existing driver. Trying again to get a driver to return.", DebugEnabled);
                            string query = "Select * From SMS_Driver Where DriverINFFile='" + name + "'";
                            LogLine(LogFile, "Running query: " + query, DebugEnabled);

                            IResultObject drivers = ExecuteNullableQuery(connection, query);
                            //IResultObject drivers = connection.QueryProcessor.ExecuteQuery(query);
                            if (drivers != null)
                            {
                                LogLine(LogFile, "Query returned an object: " + drivers.GetType().FullName, DebugEnabled);
                                foreach (IResultObject obj in drivers)
                                {
                                    return obj;
                                }
                            }
                            return null;
                        }
                    }
                }
                return null;

            }
            catch (SmsQueryException qex)
            {
                LogLine(LogFile, "Exception occurred in ImportOemDriver() : " + qex.ExtendStatusErrorCode + "\n" + qex.Details + "\n" + qex.Data + "\n" + qex.TargetSite + "\n" + qex.InnerException + "\n" + qex.Message + "\n" + qex.StackTrace, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, qex);
                return null;
            }
            catch (Exception ex)
            {
                LogLine(LogFile, "Exception occured in ImportOemDriver().\n" + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="driver"></param>
        /// <returns></returns>
        public static string GetDriverName(IResultObject driver)
        {
            if (driver == null)
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "driver");
            }

            XmlDocument sdmpackage = new XmlDocument();
            sdmpackage.LoadXml(driver.Properties["SDMPackageXML"].StringValue);

            // Iterate over all the <DisplayName/> tags.
            foreach (XmlNode displayName in sdmpackage.GetElementsByTagName("DisplayName"))
            {
                // Grab the first one with a Text attribute not equal to null.
                if (displayName != null && displayName.Attributes["Text"] != null
                    && !string.IsNullOrEmpty(displayName.Attributes["Text"].Value))
                {
                    // Return the DisplayName text.
                    return displayName.Attributes["Text"].Value;
                }
            }
            // Default the driverName to the UniqueID.
            return driver["CI_UniqueID"].StringValue;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="sourcePath"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static IResultObject GetDriverByPathAndFile(WqlConnectionManager connection, string sourcePath, string fileName)
        {
            if (connection == null)
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "connection");
            }
            if (string.IsNullOrEmpty(sourcePath))
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "sourcePath");
            }
            if (string.IsNullOrEmpty(fileName))
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "fileName");
            }
            
            try
            {
                string query = "Select * From SMS_Driver Where DriverINFFile='" + fileName + "'";
                LogLine(LogFile, "Running query: " + query, DebugEnabled);
                IResultObject driver = null;
                //IResultObject drivers = connection.QueryProcessor.ExecuteQuery(query);
                IResultObject drivers = ExecuteNullableQuery(connection, query);
                if (drivers != null)
                {
                    LogLine(LogFile, "Query returned an object: " + drivers.GetType().FullName, DebugEnabled);
                    
                    Nullable<int> memberID = null;
                    foreach (IResultObject obj in drivers)
                    {
                        obj.AutoRefresh = true;
                        string driverPath = IntegrationKitUtilities.GetROStringProperty(obj, "ContentSourcePath");
                        if (string.IsNullOrEmpty(driverPath) == false)
                        {
                            LogLine(LogFile, "Existing driver path = " + driverPath, DebugEnabled);

                            if (string.Compare(driverPath, sourcePath, StringComparison.OrdinalIgnoreCase) == 0)
                            {
                                LogLine(LogFile, "Existing driver path matches target", DebugEnabled);

                                memberID = IntegrationKitUtilities.GetROIntegerProperty(obj, "CI_ID");
                                LogLine(LogFile, "Returning CI_ID=" + memberID, DebugEnabled);
                                break;
                            }
                        }
                    }
                    // open the instance for editing
                    if (memberID.HasValue == true)
                    {
                        LogLine(LogFile, "Getting the driver instance from SCCM for CI_ID=" + memberID, DebugEnabled);
                        
                        driver = connection.GetInstance("SMS_Driver.CI_ID=" + memberID);
                        if (driver != null)
                        {
                            LogLine(LogFile, "Existing driver object instance opened for editing.", DebugEnabled);
                        }
                        else
                        {
                            LogLine(LogFile, "Driver object was still null after GetInstance.", DebugEnabled);
                        }
                    }
                    else
                    {
                        LogLine(LogFile, "Unable to get memberID from object. Resetting the object so a new one will be created.", DebugEnabled);
                        driver = null;
                    }
                }
                else
                {
                    LogLine(LogFile, "No matching drivers found.", DebugEnabled);
                }
                return driver;
            }
            catch (SmsQueryException qex)
            {
                LogLine(LogFile, "Exception occurred in GetDriverByPathAndFile() : " + qex.ExtendStatusErrorCode + "\n" + qex.Details + "\n" + qex.Data + "\n" + qex.TargetSite + "\n" + qex.InnerException + "\n" + qex.Message + "\n" + qex.StackTrace, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, qex);
                return null;
            }
            catch (Exception ex)
            {
                LogLine(LogFile, "Exception occured in GetDriverByPathAndFile().\n" + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="sourceInf"></param>
        /// <returns></returns>
        public static IResultObject GetMatchingDriver(WqlConnectionManager connection, FileInfo sourceInf)
        {
            ArgumentNotNull(connection, "connection");
            ArgumentNotNull(sourceInf, "sourceInf");

            try
            {
                string query = "Select * From SMS_Driver Where DriverINFFile='" + sourceInf.Name + "'";
                LogLine(LogFile, "Running query: " + query, DebugEnabled);
                IResultObject driver = null;
                
                IResultObject drivers = ExecuteNullableQuery(connection, query);
                if (drivers == null)
                {
                    LogLine(LogFile, "No matching drivers found.", DebugEnabled);
                    return null;
                }

                LogLine(LogFile, "GetMatchingDriver: Query returned an object: " + drivers.GetType().FullName, DebugEnabled);

                //convert the source INF to XML and get the name of the catalog file
                XmlDocument sourceInfXml = new XmlDocument();
                sourceInfXml.LoadXml(ConvertInfToXml(sourceInf.FullName));

                LogLine(LogFile, "Converted " + sourceInf.Name + " to XML format." , DebugEnabled);

                
                

                //modified 5/13/09 by rhearn - fix for issue 4390
                //  This code currently relies only on the existence of a .CAT file associated with a driver,
                //  which may not always exist, even if named in the INF file. As a fallback method of matching
                //  the driver, the INF file itself will be hashed to determine if this is a matching driver.
                //  The code will no longer return null solely if a catalog file name or file was not found.
                
                XmlNode catalogNode = null;
                string hashFileName = string.Empty;

                //branch depending on if source file is INF or OEM
                if (sourceInf.Extension.ToLowerInvariant().EndsWith("inf"))
                {
                    catalogNode = GetXmlNode(sourceInfXml, "//Key[translate(@Name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') = 'catalogfile']");
                    //if (catalogNode == null) return null;
                    if (catalogNode != null)
                    {
                        hashFileName = GetXmlAttribute(catalogNode, "Value");
                        if (string.IsNullOrEmpty(hashFileName) == false)
                        {
                            LogLine(LogFile, "Found catalog file info. File name is : " + hashFileName, DebugEnabled);
                        }
                    }
                    else
                    {
                        LogLine(LogFile, "Catalog file name not found in the INF file", DebugEnabled);
                    }
                }
                else if (sourceInf.Extension.ToLowerInvariant().EndsWith("oem"))
                {
                    XmlNode infNode = GetXmlNode(sourceInfXml, "//Key[translate(@Name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') ='inf' and contains(translate(@value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') ,'" + sourceInf.Name.ToLowerInvariant() + "']");
                    if (infNode != null)
                    {
                        //found the section with the INF file in it. Now find the catalog name
                        catalogNode = GetXmlNode(infNode.ParentNode, "./Key[translate(@Name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') = 'catalog']");
                        if (catalogNode != null)
                        {
                            hashFileName = GetXmlAttribute(catalogNode, "Value");
                            if (string.IsNullOrEmpty(hashFileName) == false)
                            {
                                //strip off anything other than the file name
                                if (hashFileName.IndexOf(",") > 0)
                                {
                                    hashFileName = hashFileName.Substring(hashFileName.IndexOf(",") + 1).Trim();
                                }
                                LogLine(LogFile, "Found catalog file info. File name is : " + hashFileName, DebugEnabled);
                            }
                            else
                            {
                                LogLine(LogFile, "Catalog file name not found in the OEM file", DebugEnabled);
                            }
                        }
                        else
                        {
                            LogLine(LogFile, "Could not find 'catalog' key for this file. Will revert to hashing OEM file.", DebugEnabled);
                            //return null;
                        }
                    }
                    else
                    {
                        LogLine(LogFile, "Could not find key name 'inf' containing the file name '" + sourceInf.Name + "'", DebugEnabled);
                        //return null;
                    }
                }
                else
                {
                    //not a valid file extension
                    LogLine(LogFile, "File extension was not INF or OEM. This is not valid.", DebugEnabled);
                    return null;
                }

                string sourceHashFilePath = Path.Combine(sourceInf.DirectoryName, hashFileName);
                LogLine(LogFile, "Checking for existence of file to hash (" + sourceHashFilePath + ")", DebugEnabled);
                
                if (File.Exists(sourceHashFilePath) == false)
                {
                    LogLine(LogFile, "Could not find the catalog file to hash (" + sourceHashFilePath + ")", DebugEnabled);
                    hashFileName = string.Empty;
                    sourceHashFilePath = string.Empty;
                    //return null;
                }

                if (string.IsNullOrEmpty(hashFileName))
                {
                    LogLine(LogFile, "Could not find a catalog file for the driver. Will revert to hashing the " + sourceInf.Name + " file.", DebugEnabled);
                    hashFileName = sourceInf.Name;
                    sourceHashFilePath = Path.Combine(sourceInf.DirectoryName, hashFileName);
                    if (File.Exists(sourceHashFilePath) == false)
                    {
                        LogLine(LogFile, "Could not find the file to hash (" + sourceHashFilePath + ")", DebugEnabled);
                        return null;
                    }
                }

                if (string.IsNullOrEmpty(sourceHashFilePath))
                {
                    return null;
                }

                string sourceHash = IntegrationKitUtilities.GenerateSHA1Hash(sourceHashFilePath);

                Nullable<int> memberID = null;
                foreach (IResultObject obj in drivers)
                {
                    obj.AutoRefresh = true;
                    string driverPath = IntegrationKitUtilities.GetROStringProperty(obj, "ContentSourcePath");
                    if (string.IsNullOrEmpty(driverPath) == true)
                    {
                        LogLine(LogFile, "Could not get the path to the existing driver directory", DebugEnabled);
                        continue;
                    }
                    string destHashFilePath = Path.Combine(driverPath, hashFileName);
                    
                    if (File.Exists(destHashFilePath) == false)
                    {
                        LogLine(LogFile, "Could not get the path to the existing file to hash : " + destHashFilePath, DebugEnabled);
                        continue;
                    }
                    LogLine(LogFile, "GetMatchingDriver: Existing driver path = " + destHashFilePath, DebugEnabled);

                    string destHash = IntegrationKitUtilities.GenerateSHA1Hash(destHashFilePath);
                    LogLine(LogFile, "GetMatchingDriver: Hash value of existing file = '" + destHash + "'", DebugEnabled);
                    LogLine(LogFile, "GetMatchingDriver: Hash value of source file   = '" + sourceHash + "'", DebugEnabled);
                
                    if (string.Compare(sourceHash, destHash, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        LogLine(LogFile, "GetMatchingDriver: Found the matching driver", DebugEnabled);
                        memberID = IntegrationKitUtilities.GetROIntegerProperty(obj, "CI_ID");
                        LogLine(LogFile, "GetMatchingDriver: Returning CI_ID=" + memberID, DebugEnabled);
                        break;
                    }
                    
                }
                // open the instance for editing
                if (memberID.HasValue == true)
                {
                    LogLine(LogFile, "GetMatchingDriver: Getting the driver instance from SCCM for CI_ID=" + memberID, DebugEnabled);

                    driver = connection.GetInstance("SMS_Driver.CI_ID=" + memberID);
                    if (driver != null)
                    {
                        LogLine(LogFile, "GetMatchingDriver: Existing driver object instance opened for editing.", DebugEnabled);
                    }
                    else
                    {
                        LogLine(LogFile, "GetMatchingDriver: Driver object was still null after GetInstance.", DebugEnabled);
                    }
                }
                else
                {
                    LogLine(LogFile, "GetMatchingDriver: Unable to get memberID from object. Resetting the object so a new one will be created.", DebugEnabled);
                    driver = null;
                }
            
                return driver;
            }
            catch (SmsQueryException qex)
            {
                LogLine(LogFile, "Exception occurred in GetMatchingDriver() : " + qex.ExtendStatusErrorCode + "\n" + qex.Details + "\n" + qex.Data + "\n" + qex.TargetSite + "\n" + qex.InnerException + "\n" + qex.Message + "\n" + qex.StackTrace, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, qex);
                return null;
            }
            catch (Exception ex)
            {
                LogLine(LogFile, "Exception occured in GetMatchingDriver().\n" + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="driverId"></param>
        /// <param name="force"></param>
        /// <returns></returns>
        public static bool DeleteDriver(WqlConnectionManager connection, int driverId, bool force)
        {
            ArgumentNotNull(connection, "connection");
            ArgumentGreaterThanZero(driverId, "driverId");

            try
            {
                LogLine(LogFile, "Now in DeleteDriver()", DebugEnabled);
                // modified 2/4/09 by rhearn:
                // - changed to ensure that driver is not deleted if it currently exists in driver packages
                //   - developers should ensure the driver package is deleted first.
                //   - this prevents one developer from removing a driver needed by someone else just because they share the driver
                
                //   - HOWEVER, the "force" option (when true) allows removing the driver even if it exists in other packages (it skips the check).
                if (force == false)
                {
                    // Check to see if the driver is in any packages
                    List<string> pkgList = GetPackagesContainingDriver(connection, driverId);
                    if (pkgList.Count > 0)
                    {
                        LogLine(LogFile, "This driver is still associated with one or more packages. Not deleting the driver.", DebugEnabled);
                        return true;
                    }
                    // Check to see if the driver is contained in any boot images
                    List<string> imageList = GetBootImagesContainingDriver(connection, driverId);
                    if (imageList.Count > 0)
                    {
                        LogLine(LogFile, "This driver is still associated with one or more packages. Not deleting the driver.", DebugEnabled);
                        return true;
                    }
                }
                // Get the driver.
                IResultObject driver = connection.GetInstance("SMS_Driver.CI_ID=" + driverId);
                if (driver == null)
                {
                    LogLine(LogFile, "Could not get an instance of the driver, ID # " + driverId, DebugEnabled);
                    return false;
                }

                LogLine(LogFile, "Deleting driver " + driverId, DebugEnabled);
                        
                // Delete the driver.
                driver.Delete();
                return true;
            }
            catch (SmsException ex)
            {
                LogLine(LogFile, "Failed to delete driver: " + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="driverId"></param>
        /// <returns></returns>
        public static bool DeleteDriver(WqlConnectionManager connection, int driverId)
        {
            //this method here for backward-compatibility
            return DeleteDriver(connection, driverId, false);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="driverId"></param>
        /// <param name="enableDriver"></param>
        public static void EnableDriver(WqlConnectionManager connection, int driverId, bool enableDriver)
        {
            try
            {
                // Get the driver.
                IResultObject driver = connection.GetInstance("SMS_Driver.CI_ID=" + driverId);

                // Set the flag.
                driver["IsEnabled"].BooleanValue = enableDriver;

                // Commit the changes.
                driver.AutoCommit = true;
                driver.Put();
            }
            catch (SmsException ex)
            {
                LogLine(LogFile, "Failed: " + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                //throw;
            }
        }
        
      



        //Categories

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="categoryName"></param>
        /// <returns></returns>
        public static IResultObject CreateDriverCategory(WqlConnectionManager connection, string categoryName)
        {
            try
            {
                if (string.IsNullOrEmpty(categoryName))
                {
                    throw new System.ArgumentException("categoryName", Properties.Resources.Error_InvalidParameter);
                }
                if (connection == null)
                {
                    throw new System.ArgumentException("connection", Properties.Resources.Error_InvalidParameter);
                }
                LogLine(LogFile, "Now in CreateDriverCategory()", DebugEnabled);

                IResultObject categoryObject = null;
                Nullable<int> categoryID = GetCategoryID(connection, categoryName);
                if (categoryID.HasValue)
                {
                    LogLine(LogFile, "Category already exists", DebugEnabled);
                    categoryObject = connection.GetInstance("SMS_CategoryInstance.CategoryInstanceID=" + (int)categoryID.Value);
                    if (categoryObject == null)
                    {
                        LogLine(LogFile, "Unable to retrieve category!", DebugEnabled);
                        return null;
                    }
                    return categoryObject;
                }

                //category doesn't exist....create it
                categoryObject = connection.CreateInstance("SMS_CategoryInstance");

                if (categoryObject == null)
                {
                    LogLine(LogFile, "Category item object was still null after CreateInstance.", DebugEnabled);
                    return null;
                }
                LogLine(LogFile, "New Category item object instance created.", DebugEnabled);


                categoryObject["CategoryTypeName"].StringValue = "DriverCategories";
                categoryObject["ParentCategoryInstanceID"].IntegerValue = 0;
                categoryObject["CategoryInstance_UniqueID"].StringValue = "DriverCategories" + ":" + Guid.NewGuid();



                List<IResultObject> localizedProperties = categoryObject.GetArrayItems("LocalizedInformation");

                IResultObject localizedProperty = connection.CreateEmbeddedObjectInstance("SMS_Category_LocalizedProperties");
                localizedProperty["CategoryInstanceName"].StringValue = categoryName;
                localizedProperty["LocaleID"].IntegerValue = 1033;
                localizedProperties.Add(localizedProperty);
                categoryObject.SetArrayItems("LocalizedInformation", localizedProperties);

                categoryObject.AutoCommit = true;
                categoryObject.Put();
                categoryObject.AutoRefresh = true;
                categoryObject.Get();
                return categoryObject;

            }
            catch (SmsQueryException qex)
            {
                LogLine(LogFile, "Exception occurred in CreateDriverCategory() : " + qex.ExtendStatusErrorCode + "\n" + qex.Details + "\n" + qex.Data + "\n" + qex.TargetSite + "\n" + qex.InnerException + "\n" + qex.Message + "\n" + qex.StackTrace, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, qex);
                return null;
            }
            catch (Exception ex)
            {
                LogLine(LogFile, "Exception occured in CreateDriverCategory().\n" + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="categoryName"></param>
        /// <returns></returns>
        public static bool DeleteDriverCategory(WqlConnectionManager connection, string categoryName)
        {
            return DeleteDriverCategory(connection, categoryName, false);
        }

       /// <summary>
       /// 
       /// </summary>
       /// <param name="connection"></param>
       /// <param name="categoryName"></param>
       /// <param name="force"></param>
       /// <returns></returns>
        public static bool DeleteDriverCategory(WqlConnectionManager connection, string categoryName, bool force)
        {
            try
            {
                if (string.IsNullOrEmpty(categoryName))
                {
                    throw new System.ArgumentNullException("categoryName", Properties.Resources.Error_InvalidParameter);
                }
                if (connection == null)
                {
                    throw new System.ArgumentNullException("connection", Properties.Resources.Error_InvalidParameter);
                }

                // get the list of all categories
                string query = "SELECT * From SMS_CategoryInstance WHERE CategoryTypeName = 'DriverCategories' AND LocalizedCategoryInstanceName = '" + FixWmiQueryString(categoryName) + "'";
                IResultObject results = ExecuteNullableQuery(connection, query);
                
                if (results == null)
                {
                    LogLine(LogFile, "Category does not exist!", DebugEnabled);
                    return false;
                }
                foreach (IResultObject cat in results)
                {
                    //modified 2/5/09 by rhearn to ensure categories are not removed when they are still in use by some drivers.
                    int? catId = GetROIntegerProperty(cat, "CategoryInstanceID");
                    if (catId.HasValue)
                    {
                        query = "SELECT * From SMS_CIAllCategories  WHERE CIAllCategories  = '" + catId.Value +  "'";
                        IResultObject ro = ExecuteNullableQuery(connection, query);
                        if (ro == null)
                        {
                            // category is not used for any drivers
                            cat.Delete();
                        }
                        else
                        {
                            if (force == true)
                            {
                                LogLine(LogFile, "Category is in use by some drivers, but 'force' option is true. Deleting the category.", DebugEnabled); 
                                cat.Delete();
                            }
                            else
                            {
                                LogLine(LogFile, "Category is in use by some drivers. Not removing.", DebugEnabled);
                            }
                        }
                    }
                
                }
                return true;

            }
            catch (Exception ex)
            {
                LogLine(LogFile, "Failed to delete the category" + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="driver"></param>
        /// <param name="categoryName"></param>
        /// <returns></returns>
        public static IResultObject AddDriverToCategory(WqlConnectionManager connection, IResultObject driver, string categoryName)
        {
            try
            {
                if (connection == null)
                {
                    throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "connection");
                }
                if (string.IsNullOrEmpty(categoryName))
                {
                    throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "categoryName");
                }
                if (driver == null)
                {
                    throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "driver");
                }
                LogLine(LogFile, "Now in AddDriverToCategory\n", DebugEnabled);

                string categoryGUID = string.Empty;
                IResultObject categoryObject = CreateDriverCategory(connection, categoryName);
                if (categoryObject == null)
                {
                    LogLine(LogFile, "Unable to create category\n", DebugEnabled);
                    return null;
                }
                categoryGUID = IntegrationKitUtilities.GetROStringProperty(categoryObject, "CategoryInstance_UniqueID");

                if (string.IsNullOrEmpty(categoryGUID))
                {
                    LogLine(LogFile, "Unable to create category\n", DebugEnabled);
                    return null;
                }

                LogLine(LogFile, "Categories assigned to this driver already:", DebugEnabled);
                ArrayList driverCategories = new ArrayList(driver["CategoryInstance_UniqueIDs"].StringArrayValue);

                foreach (string driverCategory in driverCategories)
                {
                    LogLine(LogFile, " >> " + driverCategory, DebugEnabled);
                    // Do nothing if the driver already has the category.
                    if (categoryGUID == driverCategory)
                    {
                        LogLine(LogFile, "Already exists\n", DebugEnabled);
                        return driver;
                    }
                }
                // Add the category to the action.
                driverCategories.Add(categoryGUID);
                LogLine(LogFile, "Adding '" + categoryGUID + "' = to the driver\n", DebugEnabled);


                // Update the driver.
                driver["CategoryInstance_UniqueIDs"].StringArrayValue = (string[])driverCategories.ToArray(typeof(string));
                driver.AutoCommit = true;
                driver.Put();
                driver.Get();
                driver.AutoRefresh = true;

                //LogLine(LogFile, "Verifying the driver was added to the list.\n");
                //driverCategories = new ArrayList(driver["CategoryInstance_UniqueIDs"].StringArrayValue);
                //foreach (string driverCategory in driverCategories)
                //{
                //    LogLine(LogFile, " >> " + driverCategory);
                //}

                return driver;

            }
            catch (SmsException ex)
            {
                LogLine(LogFile, "Failed to add the category" + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="categoryName"></param>
        /// <returns></returns>
        public static Nullable<int> GetCategoryID(WqlConnectionManager connection, string categoryName)
        {
            try
            {
                if (connection == null)
                {
                    throw new System.ArgumentException("connection", Properties.Resources.Error_InvalidParameter);
                }
                if (string.IsNullOrEmpty(categoryName))
                {
                    throw new System.ArgumentException("categoryName", Properties.Resources.Error_InvalidParameter);
                }

                LogLine(LogFile, "Now in AddDriverToCategory\n", DebugEnabled);
                string query = "SELECT * From SMS_CategoryInstance WHERE LocalizedCategoryInstanceName = '" + FixWmiQueryString(categoryName) + "'";
                IResultObject results = ExecuteNullableQuery(connection, query);
                //IResultObject results = connection.QueryProcessor.ExecuteQuery(query);

                Nullable<int> categoryInstanceID = null;
                foreach (IResultObject category in results)
                {
                    categoryInstanceID = IntegrationKitUtilities.GetROIntegerProperty(category, "CategoryInstanceID");
                    break;
                }

                if (categoryInstanceID.HasValue == false)
                {
                    LogLine(LogFile, "Category not found in master list\n", DebugEnabled);
                    return null;
                }
                LogLine(LogFile, "Category ID found : " + categoryInstanceID + "\n", DebugEnabled);
                return categoryInstanceID.Value;

            }
            catch (SmsQueryException qex)
            {
                LogLine(LogFile, "Exception occurred in ImportInfDriver() : " + qex.ExtendStatusErrorCode + "\n" + qex.Details + "\n" + qex.Data + "\n" + qex.TargetSite + "\n" + qex.InnerException + "\n" + qex.Message + "\n" + qex.StackTrace, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, qex);
                return null;
            }
            catch (Exception ex)
            {
                LogLine(LogFile, "Exception occured in ImportInfDriver().\n" + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }


        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="driver"></param>
        /// <param name="categoryName"></param>
        /// <returns></returns>
        public static int RemoveDriverFromCategory(WqlConnectionManager connection, IResultObject driver, string categoryName)
        {
            try
            {
                if (string.IsNullOrEmpty(categoryName))
                {
                    throw new System.ArgumentException("categoryName", Properties.Resources.Error_InvalidParameter);
                }
                if (driver == null)
                {
                    throw new System.ArgumentException("driver", Properties.Resources.Error_InvalidParameter);
                }

                // Get the category.
                string query = "SELECT * From SMS_CategoryInstance WHERE LocalizedCategoryInstanceName = '" + FixWmiQueryString(categoryName) + "'";
                IResultObject results =ExecuteNullableQuery(connection, query);
                //IResultObject results = connection.QueryProcessor.ExecuteQuery(query);

                ArrayList driverCategories = new ArrayList(driver["CategoryInstance_UniqueIDs"].StringArrayValue);

                // Remove the category from the driver.
                foreach (IResultObject category in results)
                {
                    driverCategories.Remove(category["CategoryInstance_UniqueID"].StringValue);
                }

                // Update the driver.
                driver["CategoryInstance_UniqueIDs"].StringArrayValue = (string[])driverCategories.ToArray(typeof(string));
                driver.AutoCommit = true;
                driver.Put();
                return 0;
            }
            catch (SmsException ex)
            {
                LogLine(LogFile, "Failed to remove category :" + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return 1;
            }
        }

        

        //Driver packages

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="packageName"></param>
        /// <param name="packageDescription"></param>
        /// <param name="packageSourcePath"></param>
        /// <param name="packageMfr"></param>
        /// <param name="packageVersion"></param>
        /// <returns></returns>
        public static IResultObject CreateDriverPackage(WqlConnectionManager connection, string packageName, string packageDescription, string packageSourcePath, string packageMfr, string packageVersion)
        {
            try
            {
                if (connection == null)
                {
                    throw new System.ArgumentNullException("connection", Properties.Resources.Error_InvalidParameter);
                }
                if (string.IsNullOrEmpty(packageName))
                {
                    throw new System.ArgumentNullException("packageName", Properties.Resources.Error_InvalidParameter);
                }
                if (Directory.Exists(packageSourcePath) == false)
                {
                    //throw new DirectoryNotFoundException("Package source path doesn't exist");
                    return null;
                }
                if (packageName.Length > 50)
                {
                    LogLine(LogFile, "Package name must be less than 50 characters. Truncating...", DebugEnabled);
                    packageName = packageName.Remove(50);
                }

                IResultObject newPackage = null;
                // first check and see if there is a duplicate package = if so, use that one and update it
                IResultObject newPackages = GetPackageByName(connection, packageName, PackageType.DriverPackage, null);
                if (newPackages != null)
                {
                    foreach (IResultObject obj in newPackages)
                    {
                        newPackage = obj;
                        break;
                    }
                }

                if (newPackage != null)
                {
                    string newPackageID = IntegrationKitUtilities.GetROStringProperty(newPackage, "PackageID");
                    if (string.IsNullOrEmpty(newPackageID) == false)
                    {
                        LogLine(LogFile, "Existing package will be updated.", DebugEnabled);
                        newPackage = connection.GetInstance(@"SMS_DriverPackage.PackageID='" + newPackageID + "'");
                    }
                }
                else
                {
                    // Create new package object.
                    newPackage = connection.CreateInstance("SMS_DriverPackage");
                    if (newPackage == null)
                    {
                        LogLine(LogFile, "new package object was null after CreateInstance.", DebugEnabled);
                        return null;
                    }
                    LogLine(LogFile, "New package object instance created.", DebugEnabled);
                }

                newPackage["Name"].StringValue = packageName;
                newPackage["Description"].StringValue = packageDescription;
                newPackage["PkgSourceFlag"].IntegerValue = (int)PackageSourceFlag.StorageDirect;
                newPackage["PkgSourcePath"].StringValue = packageSourcePath;
                newPackage["Manufacturer"].StringValue = packageMfr;
                newPackage["Version"].StringValue = packageVersion;
                newPackage["PackageType"].IntegerValue = (int)PackageType.DriverPackage;
                newPackage["PkgFlags"].IntegerValue = 0;

                // Save new package and new package properties.
                newPackage.AutoCommit = true;
                newPackage.Put();
                newPackage.AutoRefresh = true;
                newPackage.Get();
                return newPackage;

            }
            catch (SmsQueryException qex)
            {
                LogLine(LogFile, "Exception occurred in CreateDriverPackage() : " + qex.ExtendStatusErrorCode + "\n" + qex.Details + "\n" + qex.Data + "\n" + qex.TargetSite + "\n" + qex.InnerException + "\n" + qex.Message + "\n" + qex.StackTrace, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, qex);
                return null;
            }
            catch (Exception ex)
            {
                LogLine(LogFile, "Exception occured in CreateDriverPackage().\n" + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="driver"></param>
        /// <param name="driverPackage"></param>
        /// <returns></returns>
        public static IResultObject AddDriverToDriverPackage(WqlConnectionManager connection, IResultObject driver, IResultObject driverPackage)
        {
            if (connection == null)
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "connection");
            }
            if (driver == null)
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "driver");
            }
            if (driverPackage == null)
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "driverPackage");
            }

            try
            {
                LogLine(LogFile, "Now in AddDriverToDriverPackage() ", DebugEnabled);
                Nullable<int> driverId = GetROIntegerProperty(driver, "CI_ID");

                if (driverId.HasValue == false)
                {
                    return null;
                }

                // Get the list of driver content files associated with the driver
                List<int> contentIDs = new List<int>();
                string query = "Select * from SMS_CIToContent where CI_ID=" + driverId.Value;
                //IResultObject content = connection.QueryProcessor.ExecuteQuery(query);
                IResultObject content = ExecuteNullableQuery(connection, query);
                if (content == null)
                {
                    LogLine(LogFile, "Select * from SMS_CIToContent where CI_ID='" + driverId + "' failed to get an object", DebugEnabled);
                    return null;
                }
                foreach (IResultObject ro in content)
                {
                    Nullable<int> id = GetROIntegerProperty(ro, "ContentID");
                    if (id.HasValue)
                    {
                        contentIDs.Add(id.Value);
                        LogLine(LogFile, "Added ContentID '" + id + "' to the list", DebugEnabled);
                    }
                }

                // Get the driver source path
                List<string> packageSources = new List<string>();
                string contentSourcePath = GetROStringProperty(driver, "ContentSourcePath");

                packageSources.Add(contentSourcePath);
                LogLine(LogFile, "Added contentSourcePath : " + contentSourcePath, DebugEnabled);

                // create the parameters for setting the driver into the package
                Dictionary<string, Object> inParams = new Dictionary<string, object>();
                inParams.Add("bRefreshDPs", false);
                inParams.Add("ContentIDs", contentIDs.ToArray());
                inParams.Add("ContentSourcePath", packageSources.ToArray());

                LogLine(LogFile, "Starting driverPackage.ExecuteMethod(\"AddDriverContent\", inParams)", DebugEnabled);

                // add the info to the package
                driverPackage.ExecuteMethod("AddDriverContent", inParams);
                //if (retVal != 0)
                //{
                //    LogLine(LogFile, "Return value from 'AddDriverContent' was '" + retVal + "' - which is an error.");
                //    return null;
                //}
                LogLine(LogFile, "Added driver to package", DebugEnabled);
                return driverPackage;
            }
            catch (SmsQueryException qex)
            {
                LogLine(LogFile, "SmsQueryException trying to add driver to driver package. ExtendStatusErrorCode: " + qex.ExtendStatusErrorCode, DebugEnabled);
                LogLine(LogFile, "\n" + qex.Details + "\n" + qex.Data + "\n" + qex.TargetSite + "\n" + qex.InnerException + "\n" + qex.Message + "\n" + qex.StackTrace, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, qex);
                return null;
            }
            catch (SmsException ex)
            {
                LogLine(LogFile, "Failed to add driver to driver package. Error: " + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="driver"></param>
        /// <param name="driverPackage"></param>
        /// <returns></returns>
        public static bool DeleteDriverFromDriverPackage(WqlConnectionManager connection, IResultObject driver, IResultObject driverPackage)
        {
            if (connection == null)
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "connection");
            }
            if (driver == null)
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "driver");
            }
            if (driverPackage == null)
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "driverPackage");
            }

            try
            {
                LogLine(LogFile, "Now in AddDriverToDriverPackage() ", DebugEnabled);
                Nullable<int> driverId = GetROIntegerProperty(driver, "CI_ID");

                if (driverId.HasValue == false)
                {
                    return false;
                }

                // Get the list of driver content files associated with the driver
                List<int> contentIDs = new List<int>();
                string query = "Select * from SMS_CIToContent where CI_ID=" + driverId.Value;
                IResultObject content = ExecuteNullableQuery(connection, query);
                //IResultObject content = connection.QueryProcessor.ExecuteQuery(query);
                if (content == null)
                {
                    LogLine(LogFile, "Select * from SMS_CIToContent where CI_ID='" + driverId + "' failed to get an object", DebugEnabled);
                    return false;
                }
                foreach (IResultObject driverFile in content)
                {
                    Nullable<int> driverFileId = GetROIntegerProperty(driverFile, "ContentID");
                    if (driverFileId.HasValue)
                    {
                        contentIDs.Add(driverFileId.Value);
                        LogLine(LogFile, "Added ContentID '" + driverFileId + "' to the list", DebugEnabled);
                    }
                }
                
                // create the parameters for removing the driver from the package
                Dictionary<string, Object> inParams = new Dictionary<string, object>();
                inParams.Add("ContentIDs", contentIDs.ToArray());
                inParams.Add("bRefreshDPs", false);

                // add the info to the package
                driverPackage.ExecuteMethod("RemoveDriverContent", inParams);

                LogLine(LogFile, "Removed driver from package", DebugEnabled);
                return true;
            }
            catch (SmsQueryException qex)
            {
                LogLine(LogFile, "SmsQueryException trying to add driver to driver package. ExtendStatusErrorCode: " + qex.ExtendStatusErrorCode, DebugEnabled);
                LogLine(LogFile, "\n" + qex.Details + "\n" + qex.Data + "\n" + qex.TargetSite + "\n" + qex.InnerException + "\n" + qex.Message + "\n" + qex.StackTrace, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, qex);
                return false;
            }
            catch (SmsException ex)
            {
                LogLine(LogFile, "Failed to add driver to driver package. Error: " + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="packageId"></param>
        public static bool DeleteDriverPackage(WqlConnectionManager connection, string packageId)
        {
            try
            {
                // Get the driver package.
                IResultObject driverPackage = connection.GetInstance("SMS_DriverPackage.packageId='" + packageId + "'");
                if (driverPackage == null)
                {
                    return false;
                }
                // Delete the driver package.
                driverPackage.Delete();
                return true;
            }
            catch (SmsException ex)
            {
                LogLine(LogFile, "Failed to delete driver package: " + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return false;
            }
        }

        /// <summary>
        /// Returns a list of package IDs that are driver packages containing the referenced driver ID.
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="driverId">The CI_ID of the driver</param>
        /// <returns>A string list of package IDs for the driver packages, or null if not found.</returns>
        public static List<string> GetPackagesContainingDriver(WqlConnectionManager connection, int driverId)
        {
            ArgumentNotNull(connection, "connection");
            ArgumentGreaterThanZero(driverId, "driverId");

            //Select pkg.PackageID from SMS_PackageToContent as pkg INNER JOIN SMS_CIToContent as ci ON pkg.ContentID = ci.ContentID where ci.CI_ID = 6885
            List<string> packages = new List<string>();
            IResultObject content = null;
            string query = "Select * from SMS_PackageToContent as pkg INNER JOIN SMS_CIToContent as ci ON pkg.ContentID = ci.ContentID where ci.CI_ID = " + driverId;
            try
            {
                 content = ExecuteNullableQuery(connection, query);
            }
            catch
            {
                LogLine(LogFile, "Select * from SMS_PackageToContent as pkg INNER JOIN SMS_CIToContent as ci ON pkg.ContentID = ci.ContentID where ci.CI_ID = " + driverId + "' caused an exception", DebugEnabled);
                return null;
            }
            if (content == null)
            {
                LogLine(LogFile, "Select * from SMS_PackageToContent as pkg INNER JOIN SMS_CIToContent as ci ON pkg.ContentID = ci.ContentID where ci.CI_ID = " + driverId + "' failed to get an object", DebugEnabled);
                return null;
            }
            string packageId = string.Empty;

            if (GetNumberOfChildObjects(content) > 0)
            {
                foreach (IResultObject ro in content)
                {
                    packageId = GetROStringProperty(ro, "PackageID");
                    if (string.IsNullOrEmpty(packageId) == false)
                    {
                        packages.Add(packageId);
                        LogLine(LogFile, "Added PackageID '" + packageId + "' to the list", DebugEnabled);
                    }
                }
            }
            else
            {
                packageId = GetROStringProperty(content, "PackageID");
                if (string.IsNullOrEmpty(packageId) == false)
                {
                    packages.Add(packageId);
                    LogLine(LogFile, "Added PackageID '" + packageId + "' to the list", DebugEnabled);
                }
            }
            
            return packages;

        }


        //Boot images

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="driverId"></param>
        /// <param name="bootImagePackageId"></param>
        /// <returns></returns>
        public static IResultObject AddDriverToBootImagePackage(WqlConnectionManager connection, int driverId, string bootImagePackageId)
        {
            try
            {
                // Get the boot image package.
                IResultObject bootImagePackage = connection.GetInstance(@"SMS_BootImagePackage.packageId='" + bootImagePackageId + "'");
                if (bootImagePackage == null)
                {
                    LogLine(LogFile, "AddDriverToBootImagePackage - unable to get an instance of the boot image package", DebugEnabled);
                    return null;
                }
                // Get the driver.
                IResultObject driver = connection.GetInstance("SMS_Driver.CI_ID=" + driverId);
                if (driver == null)
                {
                    LogLine(LogFile, "AddDriverToBootImagePackage - unable to get an instance of the driver", DebugEnabled);
                    return null;
                }
                
                // Get the drivers that are referenced by the package.
                List<IResultObject> referencedDrivers = bootImagePackage.GetArrayItems("ReferencedDrivers");
                LogLine(LogFile, "Created the referencedDrivers list", DebugEnabled);
                    
                // Create and populate an embedded SMS_Driver_Details. This is added to the ReferencedDrivers array.
                IResultObject driverDetails = connection.CreateEmbeddedObjectInstance("SMS_Driver_Details");
                LogLine(LogFile, "Created the driverDetails list", DebugEnabled);
                
                driverDetails["ID"].IntegerValue = driverId;
                driverDetails["SourcePath"].StringValue = IntegrationKitUtilities.GetROStringProperty(driver, "ContentSourcePath");

                LogLine(LogFile, "driverDetails.ID         = " + driverDetails["ID"].IntegerValue, DebugEnabled);
                LogLine(LogFile, "driverDetails.SourcePath = " + driverDetails["SourcePath"].StringValue, DebugEnabled);
                
                // Add the driver details to the array.
                referencedDrivers.Add(driverDetails);
                LogLine(LogFile, "Added the driver to the referencedDrivers list. Total items: " + referencedDrivers.Count, DebugEnabled);
                
                // Add the array to the boot image package.
                bootImagePackage.SetArrayItems("ReferencedDrivers", referencedDrivers);
                LogLine(LogFile, "Added the referencedDrivers list to the boot image package", DebugEnabled);
                
                // Commit the changes.
                bootImagePackage.Put();
                //bootImagePackage.ExecuteMethod("RefreshPkgSource", null);
                return bootImagePackage;

            }
            catch (SmsQueryException qex)
            {
                LogLine(LogFile, "Exception occurred in AddDriverToBootImagePackage() : " + qex.ExtendStatusErrorCode + "\n" + qex.Details + "\n" + qex.Data + "\n" + qex.TargetSite + "\n" + qex.InnerException + "\n" + qex.Message + "\n" + qex.StackTrace, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, qex);
                return null;
            }
            catch (SmsException qex)
            {
                LogLine(LogFile, "Exception occurred in AddDriverToBootImagePackage() : " + "\n" + qex.Details + "\n" + qex.Data + "\n" + qex.TargetSite + "\n" + qex.InnerException + "\n" + qex.Message + "\n" + qex.StackTrace, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, qex);
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="driver"></param>
        /// <param name="bootImagePackage"></param>
        /// <returns></returns>
        public static IResultObject AddDriverToBootImagePackage(WqlConnectionManager connection, IResultObject driver, IResultObject bootImagePackage)
        {
            try
            {
                if (connection == null)
                {
                    throw new ArgumentException("", "connection");
                } 
                if (driver == null)
                {
                    throw new ArgumentException("", "driver");
                }
                if (bootImagePackage == null)
                {
                    throw new ArgumentException("", "bootImagePackage");
                }

                // Get the drivers that are referenced by the package.
                List<IResultObject> referencedDrivers = bootImagePackage.GetArrayItems("ReferencedDrivers");

                // Create and populate an embedded SMS_Driver_Details. This is added to the ReferencedDrivers array.
                IResultObject driverDetails = connection.CreateEmbeddedObjectInstance("SMS_Driver_Details");

                driverDetails["ID"].IntegerValue = (int)IntegrationKitUtilities.GetROIntegerProperty(driver, "CI_ID");
                driverDetails["SourcePath"].StringValue = IntegrationKitUtilities.GetROStringProperty(driver, "ContentSourcePath");

                // Add the driver details to the array.
                referencedDrivers.Add(driverDetails);

                // Add the array to the boot image package.
                bootImagePackage.SetArrayItems("ReferencedDrivers", referencedDrivers);

                // Commit the changes.
                bootImagePackage.AutoCommit = true;
                bootImagePackage.Put();
                bootImagePackage.ExecuteMethod("RefreshPkgSource", null);
                bootImagePackage.Get();
                return bootImagePackage;

            }
            catch (SmsQueryException qex)
            {
                LogLine(LogFile, "Exception occurred during AddDriverToBootImagePackage. ExtendStatusErrorCode : " + qex.ExtendStatusErrorCode, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, qex);
                return null;
            }
            catch (SmsException ex)
            {
                LogLine(LogFile, "Exception occurred during AddDriverToBootImagePackage. " + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="driverId"></param>
        /// <param name="bootImagePackageId"></param>
        /// <returns></returns>
        public static bool DeleteDriverFromBootImagePackage(WqlConnectionManager connection, int driverId, string bootImagePackageId)
        {
            try
            {
                // Get the boot image package.
                IResultObject bootImagePackage = connection.GetInstance(@"SMS_BootImagePackage.packageId='" + bootImagePackageId + "'");

                // Get the (SMS_Driver_Details) drivers referenced by the package.
                List<IResultObject> referencedDrivers = bootImagePackage.GetArrayItems("ReferencedDrivers");

                foreach (IResultObject referencedDriver in referencedDrivers)
                {
                    if (referencedDriver["ID"].IntegerValue == driverId) // Remove the driver that matches driverId.
                    {
                        referencedDrivers.Remove(referencedDriver);
                        break;
                    }
                }

                bootImagePackage.SetArrayItems("ReferencedDrivers", referencedDrivers);

                // Commit the changes.
                bootImagePackage.AutoCommit = true;
                bootImagePackage.Put();
                bootImagePackage.ExecuteMethod("RefreshPkgSource", null);
                return true;
            }
            catch (SmsQueryException qex)
            {
                LogLine(LogFile, "Exception occurred during DeleteDriverFromBootImagePackage. ExtendStatusErrorCode : " + qex.ExtendStatusErrorCode, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, qex);
                return false;
            }
            catch (SmsException ex)
            {
                LogLine(LogFile, "Exception occurred during DeleteDriverFromBootImagePackage. " + ex.Message, DebugEnabled);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return false;
            }
        }

        /// <summary>
        /// Returns a list of package IDs that are boot images containing the referenced driver ID.
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="driverId">The CI_ID of the driver</param>
        /// <returns>A string list of package IDs for the boot images, or null if not found.</returns>
        public static List<string> GetBootImagesContainingDriver(WqlConnectionManager connection, int driverId)
        {
            ArgumentNotNull(connection, "connection");
            ArgumentGreaterThanZero(driverId, "driverId");

            List<string> bootImages = new List<string>();
            
            string query = "Select * FROM SMS_BootImagePackage_DriverRef where CI_ID = " + driverId;
            IResultObject content = null;
            try
            {
                content = ExecuteNullableQuery(connection, query);
            }
            catch
            {
                LogLine(LogFile, "Select * FROM SMS_BootImagePackage_DriverRef where CI_ID = " + driverId + "' caused an exception", DebugEnabled);
                return null;
            }
            if (content == null)
            {
                LogLine(LogFile, "Select * FROM SMS_BootImagePackage_DriverRef where CI_ID = " + driverId + "' failed to get an object", DebugEnabled);
                return null;
            }
            string packageId = string.Empty;

            if (GetNumberOfChildObjects(content) > 0)
            {
                foreach (IResultObject ro in content)
                {
                    packageId = GetROStringProperty(ro, "PkgID");
                    if (string.IsNullOrEmpty(packageId) == false)
                    {
                        bootImages.Add(packageId);
                        LogLine(LogFile, "Added PackageID '" + packageId + "' to the list", DebugEnabled);
                    }
                }
            }
            else
            {
                packageId = GetROStringProperty(content, "PkgID");
                if (string.IsNullOrEmpty(packageId) == false)
                {
                    bootImages.Add(packageId);
                    LogLine(LogFile, "Added PackageID '" + packageId + "' to the list", DebugEnabled);
                }
            }

            return bootImages;

        }
        
        #endregion


    }
}